Merge remote-tracking branch 'origin_myems/develop' into develop
commit
0f6a6d20c1
30
README.md
30
README.md
|
@ -22,53 +22,43 @@ MyEMS是行业领先的开源能源管理系统,利用云计算、物联网、
|
|||
## MyEMS组件(社区版)
|
||||
|
||||
MyEMS项目由下列组件构成:
|
||||
### MyEMS 数据库
|
||||
SQL
|
||||
### MyEMS 数据库 (SQL)
|
||||
|
||||
[安装 数据库](./database/README.md)
|
||||
|
||||
### MyEMS API 应用程序接口
|
||||
Python
|
||||
### MyEMS API 应用程序接口 (Python)
|
||||
|
||||
[安装 myems-api](./myems-api/README.md)
|
||||
|
||||
### MyEMS 管理 UI
|
||||
AngularJS
|
||||
### MyEMS 管理 UI (AngularJS)
|
||||
|
||||
[安装 admin UI](./admin/README.md)
|
||||
|
||||
### MyEMS BACnet/IP 数据采集服务
|
||||
Python
|
||||
### MyEMS BACnet/IP 数据采集服务 (Python)
|
||||
|
||||
[安装 myems-bacnet](./myems-bacnet/README.md)
|
||||
|
||||
### MyEMS Modbus TCP 数据采集服务
|
||||
Python
|
||||
### MyEMS Modbus TCP 数据采集服务 (Python)
|
||||
|
||||
[安装 myems-modbus-tcp](./myems-modbus-tcp/README.md)
|
||||
|
||||
### MyEMS MQTT数据转发服务
|
||||
Python
|
||||
### MyEMS MQTT数据转发服务 (Python)
|
||||
|
||||
[安装 myems-mqtt-publisher](./myems-mqtt-publisher/README.md)
|
||||
|
||||
### MyEMS 数据清洗服务
|
||||
Python
|
||||
### MyEMS 数据清洗服务 (Python)
|
||||
|
||||
[安装 myems-cleaning](./myems-cleaning/README.md)
|
||||
|
||||
### MyEMS 数据规范化服务
|
||||
Python
|
||||
### MyEMS 数据规范化服务 (Python)
|
||||
|
||||
[安装 myems-normalization](./myems-normalization/README.md)
|
||||
|
||||
### MyEMS 数据汇总服务
|
||||
Python
|
||||
### MyEMS 数据汇总服务 (Python)
|
||||
|
||||
[安装 myems-aggregation](./myems-aggregation/README.md)
|
||||
|
||||
### MyEMS Web UI
|
||||
ReactJS
|
||||
### MyEMS Web UI (ReactJS)
|
||||
|
||||
[安装 web UI](./web/README.md)
|
||||
|
||||
|
|
30
README_DE.md
30
README_DE.md
|
@ -23,53 +23,43 @@ MyEMS wird von einem erfahrenen Entwicklungsteam entwickelt und gewartet, und de
|
|||
|
||||
Dieses Projekt besteht aus folgenden Komponenten:
|
||||
|
||||
### MyEMS Database
|
||||
SQL
|
||||
### MyEMS Database (SQL)
|
||||
|
||||
[Installieren database](./database/README.md)
|
||||
|
||||
### MyEMS API
|
||||
Python
|
||||
### MyEMS API (Python)
|
||||
|
||||
[Installieren myems-api](./myems-api/README.md)
|
||||
|
||||
### MyEMS Admin UI
|
||||
AngularJS
|
||||
### MyEMS Admin UI (AngularJS)
|
||||
|
||||
[Installieren admin UI](./admin/README.md)
|
||||
|
||||
### MyEMS BACnet/IP Acquisition Service
|
||||
Python
|
||||
### MyEMS BACnet/IP Acquisition Service (Python)
|
||||
|
||||
[Installieren myems-bacnet](./myems-bacnet/README.md)
|
||||
|
||||
### MyEMS Modbus TCP Acquisition Service
|
||||
Python
|
||||
### MyEMS Modbus TCP Acquisition Service (Python)
|
||||
|
||||
[Installieren myems-modbus-tcp](./myems-modbus-tcp/README.md)
|
||||
|
||||
### MyEMS MQTT Data vorwärts Service
|
||||
Python
|
||||
### MyEMS MQTT Data vorwärts Service (Python)
|
||||
|
||||
[Installieren myems-mqtt-publisher](./myems-mqtt-publisher/README.md)
|
||||
|
||||
### MyEMS Cleaning Service
|
||||
Python
|
||||
### MyEMS Cleaning Service (Python)
|
||||
|
||||
[Installieren myems-cleaning](./myems-cleaning/README.md)
|
||||
|
||||
### MyEMS Normalization Service
|
||||
Python
|
||||
### MyEMS Normalization Service (Python)
|
||||
|
||||
[Installieren myems-normalization](./myems-normalization/README.md)
|
||||
|
||||
### MyEMS Aggregation Service
|
||||
Python
|
||||
### MyEMS Aggregation Service (Python)
|
||||
|
||||
[Installieren myems-aggregation](./myems-aggregation/README.md)
|
||||
|
||||
### MyEMS Web UI
|
||||
ReactJS
|
||||
### MyEMS Web UI (ReactJS)
|
||||
|
||||
[Installieren web UI](./web/README.md)
|
||||
|
||||
|
|
30
README_EN.md
30
README_EN.md
|
@ -23,53 +23,43 @@ MyEMS is being developed and maintained by an experienced development team, and
|
|||
|
||||
This project is compose of following components:
|
||||
|
||||
### MyEMS Database
|
||||
SQL
|
||||
### MyEMS Database (SQL)
|
||||
|
||||
[Install database](./database/README.md)
|
||||
|
||||
### MyEMS API
|
||||
Python
|
||||
### MyEMS API (Python)
|
||||
|
||||
[Install myems-api](./myems-api/README.md)
|
||||
|
||||
### MyEMS Admin UI
|
||||
ReactJS
|
||||
### MyEMS Admin UI (ReactJS)
|
||||
|
||||
[Install admin UI](./admin/README.md)
|
||||
|
||||
### MyEMS BACnet/IP Acquisition Service
|
||||
Python
|
||||
### MyEMS BACnet/IP Acquisition Service (Python)
|
||||
|
||||
[Install myems-bacnet](./myems-bacnet/README.md)
|
||||
|
||||
### MyEMS Modbus TCP Acquisition Service
|
||||
Python
|
||||
### MyEMS Modbus TCP Acquisition Service (Python)
|
||||
|
||||
[Install myems-modbus-tcp](./myems-modbus-tcp/README.md)
|
||||
|
||||
### MyEMS MQTT Data Forwarding Service
|
||||
Python
|
||||
### MyEMS MQTT Data Forwarding Service (Python)
|
||||
|
||||
[Install myems-mqtt-publisher](./myems-mqtt-publisher/README.md)
|
||||
|
||||
### MyEMS Cleaning Service
|
||||
Python
|
||||
### MyEMS Cleaning Service (Python)
|
||||
|
||||
[Install myems-cleaning](./myems-cleaning/README.md)
|
||||
|
||||
### MyEMS Normalization Service
|
||||
Python
|
||||
### MyEMS Normalization Service (Python)
|
||||
|
||||
[Install myems-normalization](./myems-normalization/README.md)
|
||||
|
||||
### MyEMS Aggregation Service
|
||||
Python
|
||||
### MyEMS Aggregation Service (Python)
|
||||
|
||||
[Install myems-aggregation](./myems-aggregation/README.md)
|
||||
|
||||
### MyEMS Web UI
|
||||
AngularJS
|
||||
### MyEMS Web UI (AngularJS)
|
||||
|
||||
[Install web UI](./web/README.md)
|
||||
|
||||
|
|
|
@ -84,6 +84,24 @@ CREATE TABLE IF NOT EXISTS `myems_fdd_db`.`tbl_rules` (
|
|||
PRIMARY KEY (`id`));
|
||||
CREATE INDEX `tbl_rules_index_1` ON `myems_fdd_db`.`tbl_rules` (`name`);
|
||||
|
||||
-- ---------------------------------------------------------------------------------------------------------------------
|
||||
-- Data for table `myems_fdd_db`.`tbl_rules`
|
||||
-- ---------------------------------------------------------------------------------------------------------------------
|
||||
-- INSERT INTO `tbl_rules` VALUES (1, '网关通讯异常报警', '31408ce8-f2ac-48bd-99c3-0466c746262b', 'SYSTEM01', 'SYSTEM', 'MEDIUM', 'EMAIL', '{\"minutes\": 30, \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}], \"not_alarm_gateway\": []}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (2, '数据点通讯异常报警', '1350d71f-64d0-4276-835b-bfdf84a86bab', 'SYSTEM02', 'SYSTEM', 'MEDIUM', 'EMAIL', '{\"minutes\": 30, \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}], \"not_alarm_points\": []}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (3, '电压电流异常报警', '947fdbfd-7915-4484-93bc-9dfe0c8622a8', 'REALTIME01', 'REALTIME', 'MEDIUM', 'EMAIL', '{\"minutes\": 30, \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}], \"not_alarm_points\": []}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (4, '数据上下限异常报警', '0f9afcad-4fbd-4978-a4ed-5bc7c85ce04e', 'SPACE01', 'SPACE', 'MEDIUM', 'EMAIL', '{\"days\": 1, \"space\": {\"name\": \"远洋太古里\", \"limit\": [[\"电\", 60, 0], [\"水\", 999, 0], [\"天然气\", 999, 0]]}, \"period\": \"day\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (5, '数据每日环比异常报警', '6f9c8f79-6495-47cb-b06f-f1d2cc767ee7', 'SPACE02', 'SPACE', 'MEDIUM', 'EMAIL', '{\"days\": 1, \"space\": {\"name\": \"远洋太古里\", \"limit\": [[\"电\", 0.6, 0.0], [\"水\", 0.99, 0.0], [\"天然气\", 0.99, 0.0]]}, \"period\": \"day\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (6, '数据每周环比异常报警', 'e3cb0824-f0fb-4563-8b5f-00b610da6b15', 'SPACE03', 'SPACE', 'MEDIUM', 'EMAIL', '{\"days\": 7, \"space\": {\"name\": \"远洋太古里\", \"limit\": [[\"电\", 0.6, 0.0], [\"水\", 0.99, 0.0], [\"天然气\", 0.99, 0.0]]}, \"period\": \"week\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (7, '数据每月环比异常报警', '005e92e7-380c-46f6-a543-7937d703d038', 'SPACE04', 'SPACE', 'MEDIUM', 'EMAIL', '{\"space\": {\"name\": \"远洋太古里\", \"limit\": [[\"电\", 0.6, 0.0], [\"水\", 0.99, 0.0], [\"天然气\", 0.99, 0.0]]}, \"months\": 1, \"period\": \"month\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (8, '数据上下限异常报警', '5c201b7c-68fd-4c86-bc50-e44ee3cf29cb', 'METER01', 'METER', 'MEDIUM', 'EMAIL', '{\"days\": 1, \"meter\": {\"name\": \"低压柜主进线#1\", \"limit\": [999, 0]}, \"period\": \"day\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (9, '数据每日环比异常报警', 'aa3a764a-e777-4a12-ac7a-89425cdff876', 'METER02', 'METER', 'MEDIUM', 'EMAIL', '{\"days\": 1, \"meter\": {\"name\": \"低压柜主进线#1\", \"limit\": [0.99, 0]}, \"period\": \"day\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (10, '数据每周环比异常报警', '1b7dd8bf-904f-417c-9552-3e9085e06b12', 'METER03', 'METER', 'MEDIUM', 'EMAIL', '{\"days\": 7, \"meter\": {\"name\": \"低压柜主进线#1\", \"limit\": [0.99, 0]}, \"period\": \"week\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (11, '数据每月环比异常报警', '8f5f1109-13b9-4b17-9b1d-ada6fa09d735', 'METER04', 'METER', 'MEDIUM', 'EMAIL', '{\"meter\": {\"name\": \"低压柜主进线#1\", \"limit\": [0.99, 0]}, \"months\": 1, \"period\": \"month\", \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (12, '数据上下限异常报警', '7a033366-72e9-41a8-9660-9f4461b6d9fb', 'TENANT01', 'TENANT', 'MEDIUM', 'EMAIL', '{\"days\": 1, \"period\": \"day\", \"tenant\": {\"name\": \"Starbucks星巴克\", \"limit\": [[\"电\", 60, 0], [\"水\", 999, 0], [\"天然气\", 999, 0]]}, \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (13, '数据每日环比异常报警', '7eb7ec13-87d2-44de-8070-d6d7ad933927', 'TENANT02', 'TENANT', 'MEDIUM', 'EMAIL', '{\"days\": 1, \"period\": \"day\", \"tenant\": {\"name\": \"Starbucks星巴克\", \"limit\": [[\"电\", 0.6, 0], [\"水\", 0.99, 0], [\"天然气\", 0.99, 0]]}, \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (14, '数据每周环比异常报警', 'c33d7123-95f7-445c-a178-13a2b0d54489', 'TENANT03', 'TENANT', 'MEDIUM', 'EMAIL', '{\"days\": 7, \"period\": \"week\", \"tenant\": {\"name\": \"Starbucks星巴克\", \"limit\": [[\"电\", 0.6, 0], [\"水\", 0.99, 0], [\"天然气\", 0.99, 0]]}, \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
-- INSERT INTO `tbl_rules` VALUES (15, '数据每月环比异常报警', '49183491-77f2-48dd-a56d-bd73e5971e1c', 'TENANT04', 'TENANT', 'MEDIUM', 'EMAIL', '{\"months\": 1, \"period\": \"month\", \"tenant\": {\"name\": \"Starbucks星巴克\", \"limit\": [[\"电\", 0.6, 0], [\"水\", 0.99, 0], [\"天然气\", 0.99, 0]]}, \"recipients\": [{\"name\": \"Johnson\", \"email\": \"johnson@myems.io\", \"mobile\": \"8613888888888\"}]}', '$s1', 1);
|
||||
|
||||
INSERT INTO `tbl_rules` VALUES (1, '网关通讯异常报警', '1', 'SYSTEM01', 'SYSTEM', 'MEDIUM', 'EMAIL', '{\"minutes\": 30, \"recipients\": [{\"name\": \"Yinghao Huang\", \"email\": \"yinghao.huang@myems.io\", \"mobile\": \"8615652962029\"}], \"not_alarm_gateway\": []}', '$s1', 1, NULL, NULL);
|
||||
INSERT INTO `tbl_rules` VALUES (2, '数据点通讯异常报警', '2', 'SYSTEM02', 'SYSTEM', 'MEDIUM', 'EMAIL', '{\"minutes\": 30, \"recipients\": [{\"name\": \"Yinghao Huang\", \"email\": \"yinghao.huang@myems.io\", \"mobile\": \"8615652962029\"}], \"not_alarm_points\": []}', '$s1', 1, NULL, NULL);
|
||||
|
|
|
@ -16,6 +16,12 @@ import statistics
|
|||
########################################################################################################################
|
||||
def aggregate_hourly_data_by_period(rows_hourly, start_datetime_utc, end_datetime_utc, period_type):
|
||||
# todo: validate parameters
|
||||
if start_datetime_utc is None or \
|
||||
end_datetime_utc is None or \
|
||||
start_datetime_utc >= end_datetime_utc or \
|
||||
period_type not in ('hourly', 'daily', 'monthly', 'yearly'):
|
||||
return list()
|
||||
|
||||
start_datetime_utc = start_datetime_utc.replace(tzinfo=None)
|
||||
end_datetime_utc = end_datetime_utc.replace(tzinfo=None)
|
||||
|
||||
|
|
|
@ -484,17 +484,19 @@ def generate_excel(report,
|
|||
|
||||
parameters_ws_current_row_number += 1
|
||||
|
||||
table_current_col_number = 'B'
|
||||
table_current_col_number = 2
|
||||
|
||||
for i in range(0, parameters_names_len):
|
||||
|
||||
if len(parameters_data['timestamps'][i]) == 0:
|
||||
continue
|
||||
|
||||
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].fill = table_fill
|
||||
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].border = f_border
|
||||
col = format_cell.get_column_letter(table_current_col_number)
|
||||
|
||||
col = chr(ord(table_current_col_number) + 1)
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].fill = table_fill
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].border = f_border
|
||||
|
||||
col = format_cell.get_column_letter(table_current_col_number + 1)
|
||||
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].fill = table_fill
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].border = f_border
|
||||
|
@ -505,14 +507,14 @@ def generate_excel(report,
|
|||
table_current_row_number = parameters_ws_current_row_number
|
||||
|
||||
for j, value in enumerate(list(parameters_data['timestamps'][i])):
|
||||
col = table_current_col_number
|
||||
col = format_cell.get_column_letter(table_current_col_number)
|
||||
|
||||
parameters_ws[col + str(table_current_row_number)].border = f_border
|
||||
parameters_ws[col + str(table_current_row_number)].font = title_font
|
||||
parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
|
||||
parameters_ws[col + str(table_current_row_number)] = value
|
||||
|
||||
col = chr(ord(col) + 1)
|
||||
col = format_cell.get_column_letter(table_current_col_number + 1)
|
||||
|
||||
parameters_ws[col + str(table_current_row_number)].border = f_border
|
||||
parameters_ws[col + str(table_current_row_number)].font = title_font
|
||||
|
@ -521,7 +523,7 @@ def generate_excel(report,
|
|||
|
||||
table_current_row_number += 1
|
||||
|
||||
table_current_col_number = chr(ord(table_current_col_number) + 3)
|
||||
table_current_col_number = table_current_col_number + 3
|
||||
|
||||
########################################################
|
||||
# parameters chart and parameters table
|
||||
|
|
|
@ -4,7 +4,6 @@ import os
|
|||
from openpyxl.chart import (
|
||||
PieChart,
|
||||
LineChart,
|
||||
BarChart,
|
||||
Reference,
|
||||
)
|
||||
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
|
||||
|
@ -432,6 +431,63 @@ def generate_excel(report,
|
|||
chart_start_row_number += 6
|
||||
ws.add_chart(line, chart_cell)
|
||||
|
||||
#####################################
|
||||
|
||||
has_associated_equipment_flag = True
|
||||
|
||||
if "associated_equipment" not in report.keys() or \
|
||||
"energy_item_names" not in report['associated_equipment'].keys() or \
|
||||
len(report['associated_equipment']["energy_item_names"]) == 0 \
|
||||
or 'associated_equipment_names_array' not in report['associated_equipment'].keys() \
|
||||
or report['associated_equipment']['associated_equipment_names_array'] is None \
|
||||
or len(report['associated_equipment']['associated_equipment_names_array']) == 0 \
|
||||
or len(report['associated_equipment']['associated_equipment_names_array'][0]) == 0:
|
||||
has_associated_equipment_flag = False
|
||||
|
||||
if has_associated_equipment_flag:
|
||||
associated_equipment = report['associated_equipment']
|
||||
|
||||
ws['B' + str(current_row_number)].font = title_font
|
||||
ws['B' + str(current_row_number)] = name + ' 相关设备数据'
|
||||
|
||||
current_row_number += 1
|
||||
table_start_row_number = current_row_number
|
||||
|
||||
ws.row_dimensions[current_row_number].height = 60
|
||||
ws['B' + str(current_row_number)].fill = table_fill
|
||||
ws['B' + str(current_row_number)].font = name_font
|
||||
ws['B' + str(current_row_number)].alignment = c_c_alignment
|
||||
ws['B' + str(current_row_number)].border = f_border
|
||||
ws['B' + str(current_row_number)] = '相关设备'
|
||||
ca_len = len(associated_equipment['energy_item_names'])
|
||||
|
||||
for i in range(0, ca_len):
|
||||
row = chr(ord('C') + i)
|
||||
ws[row + str(current_row_number)].fill = table_fill
|
||||
ws[row + str(current_row_number)].font = name_font
|
||||
ws[row + str(current_row_number)].alignment = c_c_alignment
|
||||
ws[row + str(current_row_number)].border = f_border
|
||||
ws[row + str(current_row_number)] = \
|
||||
reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
|
||||
|
||||
associated_equipment_len = len(associated_equipment['associated_equipment_names_array'][0])
|
||||
|
||||
for i in range(0, associated_equipment_len):
|
||||
current_row_number += 1
|
||||
row = str(current_row_number)
|
||||
|
||||
ws['B' + row].font = title_font
|
||||
ws['B' + row].alignment = c_c_alignment
|
||||
ws['B' + row] = associated_equipment['associated_equipment_names_array'][0][i]
|
||||
ws['B' + row].border = f_border
|
||||
|
||||
for j in range(0, ca_len):
|
||||
col = chr(ord('C') + j)
|
||||
ws[col + row].font = name_font
|
||||
ws[col + row].alignment = c_c_alignment
|
||||
ws[col + row] = round(associated_equipment['subtotals_array'][j][i], 2)
|
||||
ws[col + row].border = f_border
|
||||
|
||||
filename = str(uuid.uuid4()) + '.xlsx'
|
||||
wb.save(filename)
|
||||
|
||||
|
|
|
@ -0,0 +1,735 @@
|
|||
import base64
|
||||
import uuid
|
||||
import os
|
||||
from openpyxl.chart import (
|
||||
PieChart,
|
||||
LineChart,
|
||||
BarChart,
|
||||
Reference,
|
||||
)
|
||||
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
|
||||
from openpyxl.drawing.image import Image
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.chart.label import DataLabelList
|
||||
import openpyxl.utils.cell as format_cell
|
||||
|
||||
|
||||
####################################################################################################################
|
||||
# PROCEDURES
|
||||
# Step 1: Validate the report data
|
||||
# Step 2: Generate excel file
|
||||
# Step 3: Encode the excel file bytes to Base64
|
||||
####################################################################################################################
|
||||
|
||||
|
||||
def export(report,
|
||||
name,
|
||||
reporting_start_datetime_local,
|
||||
reporting_end_datetime_local,
|
||||
period_type):
|
||||
####################################################################################################################
|
||||
# Step 1: Validate the report data
|
||||
####################################################################################################################
|
||||
if report is None:
|
||||
return None
|
||||
print(report)
|
||||
|
||||
####################################################################################################################
|
||||
# Step 2: Generate excel file from the report data
|
||||
####################################################################################################################
|
||||
filename = generate_excel(report,
|
||||
name,
|
||||
reporting_start_datetime_local,
|
||||
reporting_end_datetime_local,
|
||||
period_type)
|
||||
####################################################################################################################
|
||||
# Step 3: Encode the excel file to Base64
|
||||
####################################################################################################################
|
||||
try:
|
||||
with open(filename, 'rb') as binary_file:
|
||||
binary_file_data = binary_file.read()
|
||||
except IOError as ex:
|
||||
pass
|
||||
|
||||
# Base64 encode the bytes
|
||||
base64_encoded_data = base64.b64encode(binary_file_data)
|
||||
# get the Base64 encoded data using human-readable characters.
|
||||
base64_message = base64_encoded_data.decode('utf-8')
|
||||
# delete the file from server
|
||||
try:
|
||||
os.remove(filename)
|
||||
except NotImplementedError as ex:
|
||||
pass
|
||||
return base64_message
|
||||
|
||||
|
||||
def generate_excel(report,
|
||||
name,
|
||||
reporting_start_datetime_local,
|
||||
reporting_end_datetime_local,
|
||||
period_type):
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
|
||||
# Row height
|
||||
ws.row_dimensions[1].height = 102
|
||||
|
||||
for i in range(2, 2000 + 1):
|
||||
ws.row_dimensions[i].height = 42
|
||||
|
||||
# Col width
|
||||
ws.column_dimensions['A'].width = 1.5
|
||||
|
||||
ws.column_dimensions['B'].width = 25.0
|
||||
|
||||
for i in range(ord('C'), ord('L')):
|
||||
ws.column_dimensions[chr(i)].width = 15.0
|
||||
|
||||
# Font
|
||||
name_font = Font(name='Constantia', size=15, bold=True)
|
||||
title_font = Font(name='宋体', size=15, bold=True)
|
||||
data_font = Font(name='Franklin Gothic Book', size=11)
|
||||
|
||||
table_fill = PatternFill(fill_type='solid', fgColor='1F497D')
|
||||
f_border = Border(left=Side(border_style='medium', color='00000000'),
|
||||
right=Side(border_style='medium', color='00000000'),
|
||||
bottom=Side(border_style='medium', color='00000000'),
|
||||
top=Side(border_style='medium', color='00000000')
|
||||
)
|
||||
b_border = Border(
|
||||
bottom=Side(border_style='medium', color='00000000'),
|
||||
)
|
||||
|
||||
b_c_alignment = Alignment(vertical='bottom',
|
||||
horizontal='center',
|
||||
text_rotation=0,
|
||||
wrap_text=True,
|
||||
shrink_to_fit=False,
|
||||
indent=0)
|
||||
c_c_alignment = Alignment(vertical='center',
|
||||
horizontal='center',
|
||||
text_rotation=0,
|
||||
wrap_text=True,
|
||||
shrink_to_fit=False,
|
||||
indent=0)
|
||||
b_r_alignment = Alignment(vertical='bottom',
|
||||
horizontal='right',
|
||||
text_rotation=0,
|
||||
wrap_text=True,
|
||||
shrink_to_fit=False,
|
||||
indent=0)
|
||||
c_r_alignment = Alignment(vertical='bottom',
|
||||
horizontal='center',
|
||||
text_rotation=0,
|
||||
wrap_text=True,
|
||||
shrink_to_fit=False,
|
||||
indent=0)
|
||||
|
||||
# Img
|
||||
img = Image("excelexporters/myems.png")
|
||||
# img = Image("myems.png")
|
||||
img.width = img.width * 1.06
|
||||
img.height = img.height * 1.06
|
||||
ws.add_image(img, 'B1')
|
||||
|
||||
# Title
|
||||
ws.row_dimensions[3].height = 60
|
||||
|
||||
ws['B3'].font = name_font
|
||||
ws['B3'].alignment = b_r_alignment
|
||||
ws['B3'] = 'Name:'
|
||||
ws['C3'].border = b_border
|
||||
ws['C3'].alignment = b_c_alignment
|
||||
ws['C3'].font = name_font
|
||||
ws['C3'] = name
|
||||
|
||||
ws['D3'].font = name_font
|
||||
ws['D3'].alignment = b_r_alignment
|
||||
ws['D3'] = 'Period:'
|
||||
ws['E3'].border = b_border
|
||||
ws['E3'].alignment = b_c_alignment
|
||||
ws['E3'].font = name_font
|
||||
ws['E3'] = period_type
|
||||
|
||||
ws['F3'].font = name_font
|
||||
ws['F3'].alignment = b_r_alignment
|
||||
ws['F3'] = 'Date:'
|
||||
ws['G3'].border = b_border
|
||||
ws['G3'].alignment = b_c_alignment
|
||||
ws['G3'].font = name_font
|
||||
ws['G3'] = reporting_start_datetime_local[:10] + "__" + reporting_end_datetime_local[:10]
|
||||
ws.merge_cells("G3:H3")
|
||||
|
||||
if "reporting_period" not in report.keys() or \
|
||||
"names" not in report['reporting_period'].keys() or len(report['reporting_period']['names']) == 0:
|
||||
filename = str(uuid.uuid4()) + '.xlsx'
|
||||
wb.save(filename)
|
||||
|
||||
return filename
|
||||
#################################################
|
||||
# First: 报告期成本分析
|
||||
# 6: title
|
||||
# 7: table title
|
||||
# 8~10 table_data
|
||||
# Total: 5 rows
|
||||
# if has not energy data: set low height for rows
|
||||
#################################################
|
||||
reporting_period_data = report['reporting_period']
|
||||
|
||||
has_energy_data_flag = True
|
||||
if "names" not in reporting_period_data.keys() or \
|
||||
reporting_period_data['names'] is None or \
|
||||
len(reporting_period_data['names']) == 0:
|
||||
has_energy_data_flag = False
|
||||
|
||||
if has_energy_data_flag:
|
||||
ws['B6'].font = title_font
|
||||
ws['B6'] = name+' 报告期成本分析'
|
||||
|
||||
category = reporting_period_data['names']
|
||||
ca_len = len(category)
|
||||
|
||||
ws.row_dimensions[7].height = 60
|
||||
ws['B7'].fill = table_fill
|
||||
ws['B7'].border = f_border
|
||||
|
||||
ws['B8'].font = title_font
|
||||
ws['B8'].alignment = c_c_alignment
|
||||
ws['B8'] = '成本'
|
||||
ws['B8'].border = f_border
|
||||
|
||||
ws['B9'].font = title_font
|
||||
ws['B9'].alignment = c_c_alignment
|
||||
ws['B9'] = '环比'
|
||||
ws['B9'].border = f_border
|
||||
|
||||
col = ''
|
||||
|
||||
for i in range(0, ca_len):
|
||||
col = chr(ord('C') + i)
|
||||
row = '7'
|
||||
cell = col + row
|
||||
ws[col + '7'].fill = table_fill
|
||||
ws[col + '7'].font = name_font
|
||||
ws[col + '7'].alignment = c_c_alignment
|
||||
ws[col + '7'] = reporting_period_data['names'][i] + " (" + reporting_period_data['units'][i] + ")"
|
||||
ws[col + '7'].border = f_border
|
||||
|
||||
ws[col + '8'].font = name_font
|
||||
ws[col + '8'].alignment = c_c_alignment
|
||||
ws[col + '8'] = round(reporting_period_data['subtotals'][i], 2)
|
||||
ws[col + '8'].border = f_border
|
||||
|
||||
ws[col + '9'].font = name_font
|
||||
ws[col + '9'].alignment = c_c_alignment
|
||||
ws[col + '9'] = str(round(reporting_period_data['increment_rates'][i] * 100, 2)) + "%" \
|
||||
if reporting_period_data['increment_rates'][i] is not None else "-"
|
||||
ws[col + '9'].border = f_border
|
||||
|
||||
col = chr(ord(col) + 1)
|
||||
|
||||
ws[col + '7'].fill = table_fill
|
||||
ws[col + '7'].font = name_font
|
||||
ws[col + '7'].alignment = c_c_alignment
|
||||
ws[col + '7'] = "总计 (" + reporting_period_data['total_unit'] + ")"
|
||||
ws[col + '7'].border = f_border
|
||||
|
||||
ws[col + '8'].font = name_font
|
||||
ws[col + '8'].alignment = c_c_alignment
|
||||
ws[col + '8'] = round(reporting_period_data['total'], 2)
|
||||
ws[col + '8'].border = f_border
|
||||
|
||||
ws[col + '9'].font = name_font
|
||||
ws[col + '9'].alignment = c_c_alignment
|
||||
ws[col + '9'] = str(round(reporting_period_data['total_increment_rate'] * 100, 2)) + "%" \
|
||||
if reporting_period_data['total_increment_rate'] is not None else "-"
|
||||
ws[col + '9'].border = f_border
|
||||
|
||||
else:
|
||||
for i in range(6, 8 + 1):
|
||||
ws.row_dimensions[i].height = 0.1
|
||||
#################################################
|
||||
# Second: 分时用电成本
|
||||
# 12: title
|
||||
# 13: table title
|
||||
# 14~17 table_data
|
||||
# Total: 6 rows
|
||||
################################################
|
||||
has_ele_peak_flag = True
|
||||
if "toppeaks" not in reporting_period_data.keys() or \
|
||||
reporting_period_data['toppeaks'] is None or \
|
||||
len(reporting_period_data['toppeaks']) == 0:
|
||||
has_ele_peak_flag = False
|
||||
|
||||
if has_ele_peak_flag:
|
||||
ws['B12'].font = title_font
|
||||
ws['B12'] = name+' 分时用电成本'
|
||||
|
||||
ws.row_dimensions[13].height = 60
|
||||
ws['B13'].fill = table_fill
|
||||
ws['B13'].font = name_font
|
||||
ws['B13'].alignment = c_c_alignment
|
||||
ws['B13'].border = f_border
|
||||
|
||||
ws['C13'].fill = table_fill
|
||||
ws['C13'].font = name_font
|
||||
ws['C13'].alignment = c_c_alignment
|
||||
ws['C13'].border = f_border
|
||||
ws['C13'] = '分时用电成本'
|
||||
|
||||
ws['B14'].font = title_font
|
||||
ws['B14'].alignment = c_c_alignment
|
||||
ws['B14'] = '尖'
|
||||
ws['B14'].border = f_border
|
||||
|
||||
ws['C14'].font = title_font
|
||||
ws['C14'].alignment = c_c_alignment
|
||||
ws['C14'].border = f_border
|
||||
ws['C14'] = round(reporting_period_data['toppeaks'][0], 2)
|
||||
|
||||
ws['B15'].font = title_font
|
||||
ws['B15'].alignment = c_c_alignment
|
||||
ws['B15'] = '峰'
|
||||
ws['B15'].border = f_border
|
||||
|
||||
ws['C15'].font = title_font
|
||||
ws['C15'].alignment = c_c_alignment
|
||||
ws['C15'].border = f_border
|
||||
ws['C15'] = round(reporting_period_data['onpeaks'][0], 2)
|
||||
|
||||
ws['B16'].font = title_font
|
||||
ws['B16'].alignment = c_c_alignment
|
||||
ws['B16'] = '平'
|
||||
ws['B16'].border = f_border
|
||||
|
||||
ws['C16'].font = title_font
|
||||
ws['C16'].alignment = c_c_alignment
|
||||
ws['C16'].border = f_border
|
||||
ws['C16'] = round(reporting_period_data['midpeaks'][0], 2)
|
||||
|
||||
ws['B17'].font = title_font
|
||||
ws['B17'].alignment = c_c_alignment
|
||||
ws['B17'] = '谷'
|
||||
ws['B17'].border = f_border
|
||||
|
||||
ws['C17'].font = title_font
|
||||
ws['C17'].alignment = c_c_alignment
|
||||
ws['C17'].border = f_border
|
||||
ws['C17'] = round(reporting_period_data['offpeaks'][0], 2)
|
||||
|
||||
pie = PieChart()
|
||||
pie.title = name+' 分时用电成本'
|
||||
labels = Reference(ws, min_col=2, min_row=14, max_row=17)
|
||||
pie_data = Reference(ws, min_col=3, min_row=13, max_row=17)
|
||||
pie.add_data(pie_data, titles_from_data=True)
|
||||
pie.set_categories(labels)
|
||||
pie.height = 7.25 # cm 1.05*5 1.05cm = 30 pt
|
||||
pie.width = 9
|
||||
# pie.title = "Pies sold by category"
|
||||
s1 = pie.series[0]
|
||||
s1.dLbls = DataLabelList()
|
||||
s1.dLbls.showCatName = False # 标签显示
|
||||
s1.dLbls.showVal = True # 数量显示
|
||||
s1.dLbls.showPercent = True # 百分比显示
|
||||
# s1 = CharacterProperties(sz=1800) # 图表中字体大小 *100
|
||||
|
||||
ws.add_chart(pie, "D13")
|
||||
|
||||
else:
|
||||
for i in range(12, 18 + 1):
|
||||
ws.row_dimensions[i].height = 0.1
|
||||
# end_row 10
|
||||
# start_row 12
|
||||
################################################
|
||||
# Second: 成本占比
|
||||
################################################
|
||||
current_row_number = 19
|
||||
|
||||
has_subtotals_data_flag = True
|
||||
|
||||
if 'subtotals' not in reporting_period_data.keys() or \
|
||||
reporting_period_data['subtotals'] is None:
|
||||
has_subtotals_data_flag = False
|
||||
|
||||
if has_subtotals_data_flag:
|
||||
ws['B' + str(current_row_number)].font = title_font
|
||||
ws['B' + str(current_row_number)] = name + ' 成本占比'
|
||||
|
||||
current_row_number += 1
|
||||
table_start_row_number = current_row_number
|
||||
|
||||
ws['B' + str(current_row_number)].fill = table_fill
|
||||
ws['B' + str(current_row_number)].font = name_font
|
||||
ws['B' + str(current_row_number)].alignment = c_c_alignment
|
||||
ws['B' + str(current_row_number)].border = f_border
|
||||
|
||||
ws['C' + str(current_row_number)].fill = table_fill
|
||||
ws['C' + str(current_row_number)].font = name_font
|
||||
ws['C' + str(current_row_number)].alignment = c_c_alignment
|
||||
ws['C' + str(current_row_number)].border = f_border
|
||||
ws['C' + str(current_row_number)] = '成本占比'
|
||||
|
||||
current_row_number += 1
|
||||
|
||||
category = reporting_period_data['names']
|
||||
ca_len = len(category)
|
||||
|
||||
for i in range(0, ca_len):
|
||||
ws['B' + str(current_row_number)].font = title_font
|
||||
ws['B' + str(current_row_number)].alignment = c_c_alignment
|
||||
ws['B' + str(current_row_number)] = reporting_period_data['names'][i] + \
|
||||
' (' + reporting_period_data['units'][i] + ')'
|
||||
ws['B' + str(current_row_number)].border = f_border
|
||||
|
||||
ws['C' + str(current_row_number)].font = title_font
|
||||
ws['C' + str(current_row_number)].alignment = c_c_alignment
|
||||
ws['C' + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 3)
|
||||
ws['C' + str(current_row_number)].border = f_border
|
||||
|
||||
current_row_number += 1
|
||||
|
||||
table_end_row_number = current_row_number - 1
|
||||
|
||||
pie = PieChart()
|
||||
pie.title = name + ' 成本占比'
|
||||
labels = Reference(ws, min_col=2, min_row=table_start_row_number + 1, max_row=table_end_row_number)
|
||||
pie_data = Reference(ws, min_col=3, min_row=table_start_row_number, max_row=table_end_row_number)
|
||||
pie.add_data(pie_data, titles_from_data=True)
|
||||
pie.set_categories(labels)
|
||||
pie.height = 6.6
|
||||
pie.width = 9
|
||||
s1 = pie.series[0]
|
||||
s1.dLbls = DataLabelList()
|
||||
s1.dLbls.showCatName = False
|
||||
s1.dLbls.showVal = True
|
||||
s1.dLbls.showPercent = True
|
||||
|
||||
ws.add_chart(pie, 'D' + str(table_start_row_number))
|
||||
|
||||
if ca_len < 4:
|
||||
current_row_number = current_row_number - ca_len + 4
|
||||
|
||||
current_row_number += 1
|
||||
|
||||
################################################
|
||||
# Fourth: 成本详情
|
||||
# current_row_number: title
|
||||
# current_row_number+1 ~ current_row_number+1+ca_len*6-1: line
|
||||
# current_row_number+1+ca_len*6: table title
|
||||
# current_row_number+1+ca_len*6~: table_data
|
||||
################################################
|
||||
reporting_period_data = report['reporting_period']
|
||||
times = reporting_period_data['timestamps']
|
||||
has_detail_data_flag = True
|
||||
ca_len = len(report['reporting_period']['names'])
|
||||
real_timestamps_len = timestamps_data_not_equal_0(report['parameters']['timestamps'])
|
||||
table_row = current_row_number + 2 + ca_len*6 + real_timestamps_len*7
|
||||
chart_start_row_number = current_row_number + 1
|
||||
if "timestamps" not in reporting_period_data.keys() or \
|
||||
reporting_period_data['timestamps'] is None or \
|
||||
len(reporting_period_data['timestamps']) == 0:
|
||||
has_detail_data_flag = False
|
||||
|
||||
if has_detail_data_flag:
|
||||
ws['B' + str(current_row_number)].font = title_font
|
||||
ws['B' + str(current_row_number)] = name+' 详细数据'
|
||||
|
||||
ws.row_dimensions[table_row].height = 60
|
||||
ws['B'+str(table_row)].fill = table_fill
|
||||
ws['B' + str(table_row)].font = title_font
|
||||
ws['B'+str(table_row)].border = f_border
|
||||
ws['B'+str(table_row)].alignment = c_c_alignment
|
||||
ws['B'+str(table_row)] = '日期时间'
|
||||
time = times[0]
|
||||
has_data = False
|
||||
max_row = 0
|
||||
if len(time) > 0:
|
||||
has_data = True
|
||||
max_row = table_row + len(time)
|
||||
print("max_row", max_row)
|
||||
|
||||
if has_data:
|
||||
for i in range(0, len(time)):
|
||||
col = 'B'
|
||||
row = str(table_row+1 + i)
|
||||
# col = chr(ord('B') + i)
|
||||
ws[col + row].font = title_font
|
||||
ws[col + row].alignment = c_c_alignment
|
||||
ws[col + row] = time[i]
|
||||
ws[col + row].border = f_border
|
||||
|
||||
for i in range(0, ca_len):
|
||||
# 38 title
|
||||
col = chr(ord('C') + i)
|
||||
|
||||
ws[col + str(table_row)].fill = table_fill
|
||||
ws[col + str(table_row)].font = title_font
|
||||
ws[col + str(table_row)].alignment = c_c_alignment
|
||||
ws[col + str(table_row)] = reporting_period_data['names'][i] + \
|
||||
" (" + reporting_period_data['units'][i] + ")"
|
||||
ws[col + str(table_row)].border = f_border
|
||||
|
||||
# 39 data
|
||||
time = times[i]
|
||||
time_len = len(time)
|
||||
|
||||
for j in range(0, time_len):
|
||||
row = str(table_row+1 + j)
|
||||
# col = chr(ord('B') + i)
|
||||
ws[col + row].font = title_font
|
||||
ws[col + row].alignment = c_c_alignment
|
||||
ws[col + row] = round(reporting_period_data['values'][i][j], 2)
|
||||
ws[col + row].border = f_border
|
||||
|
||||
current_row_number = table_row + 1 + len(times[0])
|
||||
|
||||
ws['B' + str(current_row_number)].font = title_font
|
||||
ws['B' + str(current_row_number)].alignment = c_c_alignment
|
||||
ws['B' + str(current_row_number)].border = f_border
|
||||
ws['B' + str(current_row_number)] = '小计'
|
||||
|
||||
for i in range(0, ca_len):
|
||||
col = chr(ord('C') + i)
|
||||
ws[col + str(current_row_number)].font = title_font
|
||||
ws[col + str(current_row_number)].alignment = c_c_alignment
|
||||
ws[col + str(current_row_number)].border = f_border
|
||||
ws[col + str(current_row_number)] = round(reporting_period_data['subtotals'][i], 2)
|
||||
|
||||
# line
|
||||
# 39~: line
|
||||
line = LineChart()
|
||||
line.title = '报告期消耗 - ' + ws.cell(column=3+i, row=table_row).value
|
||||
labels = Reference(ws, min_col=2, min_row=table_row+1, max_row=max_row)
|
||||
line_data = Reference(ws, min_col=3 + i, min_row=table_row, max_row=max_row) # openpyxl bug
|
||||
line.add_data(line_data, titles_from_data=True)
|
||||
line.set_categories(labels)
|
||||
line_data = line.series[0]
|
||||
line_data.marker.symbol = "circle"
|
||||
line_data.smooth = True
|
||||
line.x_axis.crosses = 'min'
|
||||
line.height = 8.25 # cm 1.05*5 1.05cm = 30 pt
|
||||
line.width = 24
|
||||
# pie.title = "Pies sold by category"
|
||||
line.dLbls = DataLabelList()
|
||||
line.dLbls.dLblPos = 't'
|
||||
# line.dLbls.showCatName = True # label show
|
||||
line.dLbls.showVal = True # val show
|
||||
line.dLbls.showPercent = True # percent show
|
||||
# s1 = CharacterProperties(sz=1800) # font size *100
|
||||
chart_col = 'B'
|
||||
chart_cell = chart_col + str(chart_start_row_number + 6*i)
|
||||
ws.add_chart(line, chart_cell)
|
||||
|
||||
current_sheet_parameters_row_number = chart_start_row_number + ca_len * 6
|
||||
##########################################
|
||||
has_parameters_names_and_timestamps_and_values_data = True
|
||||
if 'parameters' not in report.keys() or \
|
||||
report['parameters'] is None or \
|
||||
'names' not in report['parameters'].keys() or \
|
||||
report['parameters']['names'] is None or \
|
||||
len(report['parameters']['names']) == 0 or \
|
||||
'timestamps' not in report['parameters'].keys() or \
|
||||
report['parameters']['timestamps'] is None or \
|
||||
len(report['parameters']['timestamps']) == 0 or \
|
||||
'values' not in report['parameters'].keys() or \
|
||||
report['parameters']['values'] is None or \
|
||||
len(report['parameters']['values']) == 0 or \
|
||||
timestamps_data_all_equal_0(report['parameters']['timestamps']):
|
||||
|
||||
has_parameters_names_and_timestamps_and_values_data = False
|
||||
if has_parameters_names_and_timestamps_and_values_data:
|
||||
|
||||
###############################
|
||||
# new worksheet
|
||||
###############################
|
||||
|
||||
parameters_data = report['parameters']
|
||||
parameters_names_len = len(parameters_data['names'])
|
||||
|
||||
parameters_ws = wb.create_sheet('相关参数')
|
||||
|
||||
parameters_timestamps_data_max_len = \
|
||||
get_parameters_timestamps_lists_max_len(list(parameters_data['timestamps']))
|
||||
|
||||
# Row height
|
||||
parameters_ws.row_dimensions[1].height = 102
|
||||
for i in range(2, 7 + 1):
|
||||
parameters_ws.row_dimensions[i].height = 42
|
||||
|
||||
for i in range(8, parameters_timestamps_data_max_len + 10):
|
||||
parameters_ws.row_dimensions[i].height = 60
|
||||
|
||||
# Col width
|
||||
parameters_ws.column_dimensions['A'].width = 1.5
|
||||
|
||||
parameters_ws.column_dimensions['B'].width = 25.0
|
||||
|
||||
for i in range(3, 12+parameters_names_len*3):
|
||||
parameters_ws.column_dimensions[format_cell.get_column_letter(i)].width = 15.0
|
||||
|
||||
# Img
|
||||
img = Image("excelexporters/myems.png")
|
||||
img.width = img.width * 0.85
|
||||
img.height = img.height * 0.85
|
||||
# img = Image("myems.png")
|
||||
parameters_ws.add_image(img, 'B1')
|
||||
|
||||
# Title
|
||||
parameters_ws.row_dimensions[3].height = 60
|
||||
|
||||
parameters_ws['B3'].font = name_font
|
||||
parameters_ws['B3'].alignment = b_r_alignment
|
||||
parameters_ws['B3'] = 'Name:'
|
||||
parameters_ws['C3'].border = b_border
|
||||
parameters_ws['C3'].alignment = b_c_alignment
|
||||
parameters_ws['C3'].font = name_font
|
||||
parameters_ws['C3'] = name
|
||||
|
||||
parameters_ws['D3'].font = name_font
|
||||
parameters_ws['D3'].alignment = b_r_alignment
|
||||
parameters_ws['D3'] = 'Period:'
|
||||
parameters_ws['E3'].border = b_border
|
||||
parameters_ws['E3'].alignment = b_c_alignment
|
||||
parameters_ws['E3'].font = name_font
|
||||
parameters_ws['E3'] = period_type
|
||||
|
||||
parameters_ws['F3'].font = name_font
|
||||
parameters_ws['F3'].alignment = b_r_alignment
|
||||
parameters_ws['F3'] = 'Date:'
|
||||
parameters_ws['G3'].border = b_border
|
||||
parameters_ws['G3'].alignment = b_c_alignment
|
||||
parameters_ws['G3'].font = name_font
|
||||
parameters_ws['G3'] = reporting_start_datetime_local + "__" + reporting_end_datetime_local
|
||||
parameters_ws.merge_cells("G3:H3")
|
||||
|
||||
parameters_ws_current_row_number = 6
|
||||
|
||||
parameters_ws['B' + str(parameters_ws_current_row_number)].font = title_font
|
||||
parameters_ws['B' + str(parameters_ws_current_row_number)] = name + ' 相关参数'
|
||||
|
||||
parameters_ws_current_row_number += 1
|
||||
|
||||
parameters_table_start_row_number = parameters_ws_current_row_number
|
||||
|
||||
parameters_ws.row_dimensions[parameters_ws_current_row_number].height = 80
|
||||
|
||||
parameters_ws_current_row_number += 1
|
||||
|
||||
table_current_col_number = 'B'
|
||||
|
||||
for i in range(0, parameters_names_len):
|
||||
|
||||
if len(parameters_data['timestamps'][i]) == 0:
|
||||
continue
|
||||
|
||||
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].fill = table_fill
|
||||
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].border = f_border
|
||||
|
||||
col = chr(ord(table_current_col_number) + 1)
|
||||
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].fill = table_fill
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].border = f_border
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].font = name_font
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].alignment = c_c_alignment
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)] = parameters_data['names'][i]
|
||||
|
||||
table_current_row_number = parameters_ws_current_row_number
|
||||
|
||||
for j, value in enumerate(list(parameters_data['timestamps'][i])):
|
||||
col = table_current_col_number
|
||||
|
||||
parameters_ws[col + str(table_current_row_number)].border = f_border
|
||||
parameters_ws[col + str(table_current_row_number)].font = title_font
|
||||
parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
|
||||
parameters_ws[col + str(table_current_row_number)] = value
|
||||
|
||||
col = chr(ord(col) + 1)
|
||||
|
||||
parameters_ws[col + str(table_current_row_number)].border = f_border
|
||||
parameters_ws[col + str(table_current_row_number)].font = title_font
|
||||
parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
|
||||
parameters_ws[col + str(table_current_row_number)] = round(parameters_data['values'][i][j], 2)
|
||||
|
||||
table_current_row_number += 1
|
||||
|
||||
table_current_col_number = chr(ord(table_current_col_number) + 3)
|
||||
|
||||
########################################################
|
||||
# parameters chart and parameters table
|
||||
########################################################
|
||||
|
||||
ws['B' + str(current_sheet_parameters_row_number)].font = title_font
|
||||
ws['B' + str(current_sheet_parameters_row_number)] = name + ' 相关参数'
|
||||
|
||||
current_sheet_parameters_row_number += 1
|
||||
|
||||
chart_start_row_number = current_sheet_parameters_row_number
|
||||
|
||||
col_index = 0
|
||||
|
||||
for i in range(0, parameters_names_len):
|
||||
|
||||
if len(parameters_data['timestamps'][i]) == 0:
|
||||
continue
|
||||
|
||||
line = LineChart()
|
||||
data_col = 3+col_index*3
|
||||
labels_col = 2+col_index*3
|
||||
col_index += 1
|
||||
line.title = '相关参数 - ' + \
|
||||
parameters_ws.cell(row=parameters_table_start_row_number, column=data_col).value
|
||||
labels = Reference(parameters_ws, min_col=labels_col, min_row=parameters_table_start_row_number + 1,
|
||||
max_row=(len(parameters_data['timestamps'][i])+parameters_table_start_row_number))
|
||||
line_data = Reference(parameters_ws, min_col=data_col, min_row=parameters_table_start_row_number,
|
||||
max_row=(len(parameters_data['timestamps'][i])+parameters_table_start_row_number))
|
||||
line.add_data(line_data, titles_from_data=True)
|
||||
line.set_categories(labels)
|
||||
line_data = line.series[0]
|
||||
line_data.marker.symbol = "circle"
|
||||
line_data.smooth = True
|
||||
line.x_axis.crosses = 'min'
|
||||
line.height = 8.25
|
||||
line.width = 24
|
||||
line.dLbls = DataLabelList()
|
||||
line.dLbls.dLblPos = 't'
|
||||
line.dLbls.showVal = False
|
||||
line.dLbls.showPercent = False
|
||||
chart_col = 'B'
|
||||
chart_cell = chart_col + str(chart_start_row_number)
|
||||
chart_start_row_number += 6
|
||||
ws.add_chart(line, chart_cell)
|
||||
|
||||
current_sheet_parameters_row_number = chart_start_row_number
|
||||
|
||||
current_sheet_parameters_row_number += 1
|
||||
##########################################
|
||||
filename = str(uuid.uuid4()) + '.xlsx'
|
||||
wb.save(filename)
|
||||
|
||||
return filename
|
||||
|
||||
|
||||
def timestamps_data_all_equal_0(lists):
|
||||
for i, value in enumerate(list(lists)):
|
||||
if len(value) > 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_parameters_timestamps_lists_max_len(parameters_timestamps_lists):
|
||||
max_len = 0
|
||||
for i, value in enumerate(list(parameters_timestamps_lists)):
|
||||
if len(value) > max_len:
|
||||
max_len = len(value)
|
||||
|
||||
return max_len
|
||||
|
||||
|
||||
def timestamps_data_not_equal_0(lists):
|
||||
number = 0
|
||||
for i, value in enumerate(list(lists)):
|
||||
if len(value) > 0:
|
||||
number += 1
|
||||
return number
|
|
@ -484,35 +484,37 @@ def generate_excel(report,
|
|||
|
||||
parameters_ws_current_row_number += 1
|
||||
|
||||
table_current_col_number = 'B'
|
||||
table_current_col_number = 2
|
||||
|
||||
for i in range(0, parameters_names_len):
|
||||
|
||||
if len(parameters_data['timestamps'][i]) == 0:
|
||||
continue
|
||||
|
||||
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].fill = table_fill
|
||||
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].border = f_border
|
||||
col = format_cell.get_column_letter(table_current_col_number)
|
||||
|
||||
col = chr(ord(table_current_col_number) + 1)
|
||||
parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
|
||||
parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
|
||||
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].fill = table_fill
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].border = f_border
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].font = name_font
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)].alignment = c_c_alignment
|
||||
parameters_ws[col + str(parameters_ws_current_row_number-1)] = parameters_data['names'][i]
|
||||
col = format_cell.get_column_letter(table_current_col_number + 1)
|
||||
|
||||
parameters_ws[col + str(parameters_ws_current_row_number - 1)].fill = table_fill
|
||||
parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
|
||||
parameters_ws[col + str(parameters_ws_current_row_number - 1)].font = name_font
|
||||
parameters_ws[col + str(parameters_ws_current_row_number - 1)].alignment = c_c_alignment
|
||||
parameters_ws[col + str(parameters_ws_current_row_number - 1)] = parameters_data['names'][i]
|
||||
|
||||
table_current_row_number = parameters_ws_current_row_number
|
||||
|
||||
for j, value in enumerate(list(parameters_data['timestamps'][i])):
|
||||
col = table_current_col_number
|
||||
col = format_cell.get_column_letter(table_current_col_number)
|
||||
|
||||
parameters_ws[col + str(table_current_row_number)].border = f_border
|
||||
parameters_ws[col + str(table_current_row_number)].font = title_font
|
||||
parameters_ws[col + str(table_current_row_number)].alignment = c_c_alignment
|
||||
parameters_ws[col + str(table_current_row_number)] = value
|
||||
|
||||
col = chr(ord(col) + 1)
|
||||
col = format_cell.get_column_letter(table_current_col_number + 1)
|
||||
|
||||
parameters_ws[col + str(table_current_row_number)].border = f_border
|
||||
parameters_ws[col + str(table_current_row_number)].font = title_font
|
||||
|
@ -521,7 +523,7 @@ def generate_excel(report,
|
|||
|
||||
table_current_row_number += 1
|
||||
|
||||
table_current_col_number = chr(ord(table_current_col_number) + 3)
|
||||
table_current_col_number = table_current_col_number + 3
|
||||
|
||||
########################################################
|
||||
# parameters chart and parameters table
|
||||
|
|
|
@ -23,11 +23,13 @@ class Reporting:
|
|||
# Step 2: query the combined equipment
|
||||
# Step 3: query energy items
|
||||
# Step 4: query associated points
|
||||
# Step 5: query base period energy input
|
||||
# Step 6: query reporting period energy input
|
||||
# Step 7: query tariff data
|
||||
# Step 8: query associated points data
|
||||
# Step 9: construct the report
|
||||
# Step 5: query associated equipments
|
||||
# Step 6: query base period energy input
|
||||
# Step 7: query reporting period energy input
|
||||
# Step 8: query tariff data
|
||||
# Step 9: query associated points data
|
||||
# Step 10: query associated equipments energy input
|
||||
# Step 11: construct the report
|
||||
####################################################################################################################
|
||||
@staticmethod
|
||||
def on_get(req, resp):
|
||||
|
@ -239,7 +241,21 @@ class Reporting:
|
|||
point_list.append({"id": row[0], "name": row[1], "units": row[2], "object_type": row[3]})
|
||||
|
||||
################################################################################################################
|
||||
# Step 5: query base period energy input
|
||||
# Step 5: query associated equipments
|
||||
################################################################################################################
|
||||
associated_equipment_list = list()
|
||||
cursor_system.execute(" SELECT e.id, e.name "
|
||||
" FROM tbl_equipments e,tbl_combined_equipments_equipments ee"
|
||||
" WHERE ee.combined_equipment_id = %s AND e.id = ee.equipment_id"
|
||||
" ORDER BY e.id ", (combined_equipment['id'],))
|
||||
rows_associated_equipments = cursor_system.fetchall()
|
||||
if rows_associated_equipments is not None and len(rows_associated_equipments) > 0:
|
||||
for row in rows_associated_equipments:
|
||||
associated_equipment_list.append({"id": row[0], "name": row[1]})
|
||||
|
||||
print(associated_equipment_list)
|
||||
################################################################################################################
|
||||
# Step 6: query base period energy input
|
||||
################################################################################################################
|
||||
base = dict()
|
||||
if energy_item_set is not None and len(energy_item_set) > 0:
|
||||
|
@ -286,7 +302,7 @@ class Reporting:
|
|||
base[energy_item_id]['subtotal'] += actual_value
|
||||
|
||||
################################################################################################################
|
||||
# Step 6: query reporting period energy input
|
||||
# Step 7: query reporting period energy input
|
||||
################################################################################################################
|
||||
reporting = dict()
|
||||
if energy_item_set is not None and len(energy_item_set) > 0:
|
||||
|
@ -353,7 +369,7 @@ class Reporting:
|
|||
reporting[energy_item_id]['offpeak'] += row[1]
|
||||
|
||||
################################################################################################################
|
||||
# Step 7: query tariff data
|
||||
# Step 8: query tariff data
|
||||
################################################################################################################
|
||||
parameters_data = dict()
|
||||
parameters_data['names'] = list()
|
||||
|
@ -379,7 +395,7 @@ class Reporting:
|
|||
parameters_data['values'].append(tariff_value_list)
|
||||
|
||||
################################################################################################################
|
||||
# Step 8: query associated points data
|
||||
# Step 9: query associated points data
|
||||
################################################################################################################
|
||||
for point in point_list:
|
||||
point_values = []
|
||||
|
@ -444,7 +460,37 @@ class Reporting:
|
|||
parameters_data['values'].append(point_values)
|
||||
|
||||
################################################################################################################
|
||||
# Step 9: construct the report
|
||||
# Step 10: query associated equipments energy input
|
||||
################################################################################################################
|
||||
associated_equipment_data = dict()
|
||||
|
||||
if energy_item_set is not None and len(energy_item_set) > 0:
|
||||
for energy_item_id in energy_item_set:
|
||||
associated_equipment_data[energy_item_id] = dict()
|
||||
associated_equipment_data[energy_item_id]['associated_equipment_names'] = list()
|
||||
associated_equipment_data[energy_item_id]['subtotals'] = list()
|
||||
for associated_equipment in associated_equipment_list:
|
||||
associated_equipment_data[energy_item_id]['associated_equipment_names'].append(
|
||||
associated_equipment['name'])
|
||||
|
||||
cursor_energy.execute(" SELECT SUM(actual_value) "
|
||||
" FROM tbl_equipment_input_item_hourly "
|
||||
" WHERE equipment_id = %s "
|
||||
" AND energy_item_id = %s "
|
||||
" AND start_datetime_utc >= %s "
|
||||
" AND start_datetime_utc < %s "
|
||||
" ORDER BY start_datetime_utc ",
|
||||
(associated_equipment['id'],
|
||||
energy_item_id,
|
||||
reporting_start_datetime_utc,
|
||||
reporting_end_datetime_utc))
|
||||
row_subtotal = cursor_energy.fetchone()
|
||||
|
||||
subtotal = Decimal(0.0) if (row_subtotal is None or row_subtotal[0] is None) else row_subtotal[0]
|
||||
associated_equipment_data[energy_item_id]['subtotals'].append(subtotal)
|
||||
|
||||
################################################################################################################
|
||||
# Step 11: construct the report
|
||||
################################################################################################################
|
||||
if cursor_system:
|
||||
cursor_system.close()
|
||||
|
@ -522,6 +568,20 @@ class Reporting:
|
|||
"values": parameters_data['values']
|
||||
}
|
||||
|
||||
result['associated_equipment'] = dict()
|
||||
result['associated_equipment']['energy_item_names'] = list()
|
||||
result['associated_equipment']['units'] = list()
|
||||
result['associated_equipment']['associated_equipment_names_array'] = list()
|
||||
result['associated_equipment']['subtotals_array'] = list()
|
||||
if energy_item_set is not None and len(energy_item_set) > 0:
|
||||
for energy_item_id in energy_item_set:
|
||||
result['associated_equipment']['energy_item_names'].append(energy_item_dict[energy_item_id]['name'])
|
||||
result['associated_equipment']['units'].append(energy_item_dict[energy_item_id]['unit_of_measure'])
|
||||
result['associated_equipment']['associated_equipment_names_array'].append(
|
||||
associated_equipment_data[energy_item_id]['associated_equipment_names'])
|
||||
result['associated_equipment']['subtotals_array'].append(
|
||||
associated_equipment_data[energy_item_id]['subtotals'])
|
||||
|
||||
# export result to Excel file and then encode the file to base64 string
|
||||
result['excel_bytes_base64'] = excelexporters.combinedequipmentenergyitem.export(result,
|
||||
combined_equipment['name'],
|
||||
|
|
|
@ -5,6 +5,7 @@ import config
|
|||
from datetime import datetime, timedelta, timezone
|
||||
from core import utilities
|
||||
from decimal import Decimal
|
||||
import excelexporters.equipmentcost
|
||||
|
||||
|
||||
class Reporting:
|
||||
|
@ -511,5 +512,9 @@ class Reporting:
|
|||
"timestamps": parameters_data['timestamps'],
|
||||
"values": parameters_data['values']
|
||||
}
|
||||
|
||||
result['excel_bytes_base64'] = excelexporters.equipmentcost.export(result,
|
||||
equipment['name'],
|
||||
reporting_start_datetime_local,
|
||||
reporting_end_datetime_local,
|
||||
period_type)
|
||||
resp.body = json.dumps(result)
|
||||
|
|
|
@ -7,30 +7,32 @@ import schedule
|
|||
|
||||
def job(logger):
|
||||
|
||||
cnx = None
|
||||
cursor = None
|
||||
cnx_historical = None
|
||||
cursor_historical = None
|
||||
try:
|
||||
cnx = mysql.connector.connect(**config.myems_historical_db)
|
||||
cursor = cnx.cursor()
|
||||
cnx_historical = mysql.connector.connect(**config.myems_historical_db)
|
||||
cursor_historical = cnx_historical.cursor()
|
||||
except Exception as e:
|
||||
logger.error("Error in clean analog value process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
return
|
||||
|
||||
expired_utc = datetime.utcnow() - timedelta(days=config.live_in_days)
|
||||
try:
|
||||
cursor.execute(" DELETE FROM tbl_analog_value WHERE utc_date_time < %s ", (expired_utc,))
|
||||
cnx.commit()
|
||||
cursor_historical.execute(" DELETE "
|
||||
" FROM tbl_analog_value "
|
||||
" WHERE utc_date_time < %s ", (expired_utc,))
|
||||
cnx_historical.commit()
|
||||
except Exception as e:
|
||||
logger.error("Error in delete_expired_trend process " + str(e))
|
||||
finally:
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
|
||||
logger.info("Deleted trend before date time in UTC: " + expired_utc.isoformat()[0:19])
|
||||
|
||||
|
|
|
@ -7,30 +7,32 @@ import schedule
|
|||
|
||||
def job(logger):
|
||||
|
||||
cnx = None
|
||||
cursor = None
|
||||
cnx_historical = None
|
||||
cursor_historical = None
|
||||
try:
|
||||
cnx = mysql.connector.connect(**config.myems_historical_db)
|
||||
cursor = cnx.cursor()
|
||||
cnx_historical = mysql.connector.connect(**config.myems_historical_db)
|
||||
cursor_historical = cnx_historical.cursor()
|
||||
except Exception as e:
|
||||
logger.error("Error in clean digital value process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
return
|
||||
|
||||
expired_utc = datetime.utcnow() - timedelta(days=config.live_in_days)
|
||||
try:
|
||||
cursor.execute(" DELETE FROM tbl_digital_value WHERE utc_date_time < %s ", (expired_utc,))
|
||||
cnx.commit()
|
||||
cursor_historical.execute(" DELETE "
|
||||
" FROM tbl_digital_value "
|
||||
" WHERE utc_date_time < %s ", (expired_utc,))
|
||||
cnx_historical.commit()
|
||||
except Exception as e:
|
||||
logger.error("Error in delete_expired_trend process " + str(e))
|
||||
finally:
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
|
||||
logger.info("Deleted trend before date time in UTC: " + expired_utc.isoformat()[0:19])
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import mysql.connector
|
||||
import config
|
||||
import time
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
########################################################################################################################
|
||||
|
@ -17,17 +17,17 @@ def process(logger):
|
|||
|
||||
while True:
|
||||
# the outermost loop to reconnect server if there is a connection error
|
||||
cnx = None
|
||||
cursor = None
|
||||
cnx_historical = None
|
||||
cursor_historical = None
|
||||
try:
|
||||
cnx = mysql.connector.connect(**config.myems_historical_db)
|
||||
cursor = cnx.cursor()
|
||||
cnx_historical = mysql.connector.connect(**config.myems_historical_db)
|
||||
cursor_historical = cnx_historical.cursor()
|
||||
except Exception as e:
|
||||
logger.error("Error at the begin of clean_energy_value.process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
|
@ -46,19 +46,20 @@ def process(logger):
|
|||
query = (" SELECT MIN(utc_date_time), MAX(utc_date_time) "
|
||||
" FROM tbl_energy_value "
|
||||
" WHERE is_bad IS NULL ")
|
||||
cursor.execute(query, ())
|
||||
row_datetime = cursor.fetchone()
|
||||
cursor_historical.execute(query, ())
|
||||
row_datetime = cursor_historical.fetchone()
|
||||
if row_datetime is not None and len(row_datetime) == 2 and \
|
||||
isinstance(row_datetime[0], datetime) and isinstance(row_datetime[1], datetime):
|
||||
min_datetime = row_datetime[0]
|
||||
# NOTE: To avoid omission mistakes, we start one hour early
|
||||
min_datetime = row_datetime[0] - timedelta(hours=1)
|
||||
max_datetime = row_datetime[1]
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Error in Step 1 of clean_energy_value.process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
time.sleep(60)
|
||||
continue
|
||||
print("min_datetime: " + min_datetime.isoformat()[0:19])
|
||||
|
@ -170,6 +171,8 @@ def process(logger):
|
|||
# 3333 2018-02-08 00:54:16 165599.015625 good
|
||||
################################################################################################################
|
||||
print("Step 2: Processing bad case 1.x")
|
||||
cnx_system = None
|
||||
cursor_system = None
|
||||
try:
|
||||
cnx_system = mysql.connector.connect(**config.myems_system_db)
|
||||
cursor_system = cnx_system.cursor(dictionary=True)
|
||||
|
@ -193,23 +196,24 @@ def process(logger):
|
|||
if cursor_system:
|
||||
cursor_system.close()
|
||||
if cnx_system:
|
||||
cnx_system.close()
|
||||
cnx_system.disconnect()
|
||||
|
||||
try:
|
||||
query = (" SELECT id, point_id, actual_value "
|
||||
" FROM tbl_energy_value "
|
||||
" WHERE utc_date_time >= %s AND utc_date_time <= %s AND is_bad IS NOT TRUE ")
|
||||
cursor.execute(query, (min_datetime, max_datetime,))
|
||||
rows_energy_values = cursor.fetchall()
|
||||
cursor_historical.execute(query, (min_datetime, max_datetime,))
|
||||
rows_energy_values = cursor_historical.fetchall()
|
||||
except Exception as e:
|
||||
logger.error("Error in step 2.2 of clean_energy_value.process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
# initialize bad list
|
||||
bad_list = list()
|
||||
|
||||
if rows_energy_values is not None and len(rows_energy_values) > 0:
|
||||
|
@ -226,14 +230,14 @@ def process(logger):
|
|||
update = (" UPDATE tbl_energy_value "
|
||||
" SET is_bad = TRUE "
|
||||
" WHERE id IN (" + ', '.join(map(str, bad_list)) + ")")
|
||||
cursor.execute(update, )
|
||||
cnx.commit()
|
||||
cursor_historical.execute(update, )
|
||||
cnx_historical.commit()
|
||||
except Exception as e:
|
||||
logger.error("Error in step 2.3 of clean_energy_value.process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
|
@ -380,14 +384,14 @@ def process(logger):
|
|||
" FROM tbl_energy_value "
|
||||
" WHERE utc_date_time >= %s AND utc_date_time <= %s AND is_bad IS NOT TRUE "
|
||||
" ORDER BY point_id, utc_date_time ")
|
||||
cursor.execute(query, (min_datetime, max_datetime,))
|
||||
rows_energy_values = cursor.fetchall()
|
||||
cursor_historical.execute(query, (min_datetime, max_datetime,))
|
||||
rows_energy_values = cursor_historical.fetchall()
|
||||
except Exception as e:
|
||||
logger.error("Error in step 3.1 of clean_energy_value.process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
|
@ -416,6 +420,7 @@ def process(logger):
|
|||
if len(current_point_value_list) > 0:
|
||||
point_value_dict[current_point_id] = current_point_value_list
|
||||
|
||||
# reinitialize bad list
|
||||
bad_list = list()
|
||||
|
||||
for point_id, point_value_list in point_value_dict.items():
|
||||
|
@ -449,14 +454,14 @@ def process(logger):
|
|||
update = (" UPDATE tbl_energy_value "
|
||||
" SET is_bad = TRUE "
|
||||
" WHERE id IN (" + ', '.join(map(str, bad_list)) + ")")
|
||||
cursor.execute(update, )
|
||||
cnx.commit()
|
||||
cursor_historical.execute(update, )
|
||||
cnx_historical.commit()
|
||||
except Exception as e:
|
||||
logger.error("Error in step 3.2 of clean_energy_value.process " + str(e))
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
time.sleep(60)
|
||||
continue
|
||||
|
||||
|
@ -544,16 +549,16 @@ def process(logger):
|
|||
" SET is_bad = FALSE "
|
||||
" WHERE utc_date_time >= %s AND utc_date_time < %s AND is_bad IS NULL ")
|
||||
# NOTE: use '<' instead of '<=' in WHERE statement because there may be some new inserted values
|
||||
cursor.execute(update, (min_datetime, max_datetime,))
|
||||
cnx.commit()
|
||||
cursor_historical.execute(update, (min_datetime, max_datetime,))
|
||||
cnx_historical.commit()
|
||||
except Exception as e:
|
||||
logger.error("Error in step 4 of clean_energy_value.process " + str(e))
|
||||
time.sleep(60)
|
||||
continue
|
||||
finally:
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if cnx:
|
||||
cnx.close()
|
||||
if cursor_historical:
|
||||
cursor_historical.close()
|
||||
if cnx_historical:
|
||||
cnx_historical.disconnect()
|
||||
|
||||
time.sleep(900)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# definition of the database
|
||||
myems_system_db = {
|
||||
'user': 'root',
|
||||
'password': '!MyEMS1',
|
||||
|
@ -18,7 +17,8 @@ myems_historical_db = {
|
|||
# indicates how long analog values and digital values will be kept in database
|
||||
# the longer days the more memory and disc space needed.
|
||||
live_in_days = 365
|
||||
# note: By default, energy values in historical db will never be deleted automatically.
|
||||
|
||||
# NOTE: By default, energy values in historical db will never be deleted automatically.
|
||||
|
||||
# indicates if the program is in debug mode
|
||||
is_debug = False
|
||||
|
|
|
@ -33,6 +33,7 @@ import { comparisonTypeOptions } from '../common/ComparisonTypeOptions';
|
|||
|
||||
|
||||
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
|
||||
const AssociatedEquipmentTable = loadable(() => import('../common/AssociatedEquipmentTable'));
|
||||
|
||||
const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
|
||||
let current_moment = moment();
|
||||
|
@ -87,6 +88,10 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
|
||||
const [detailedDataTableData, setDetailedDataTableData] = useState([]);
|
||||
const [detailedDataTableColumns, setDetailedDataTableColumns] = useState([{dataField: 'startdatetime', text: t('Datetime'), sort: true}]);
|
||||
|
||||
const [associatedEquipmentTableData, setAssociatedEquipmentTableData] = useState([]);
|
||||
const [associatedEquipmentTableColumns, setAssociatedEquipmentTableColumns] = useState([{dataField: 'name', text: t('Associated Equipment'), sort: true }]);
|
||||
|
||||
const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -291,6 +296,7 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
|
||||
// Reinitialize tables
|
||||
setDetailedDataTableData([]);
|
||||
setAssociatedEquipmentTableData([]);
|
||||
|
||||
let isResponseOK = false;
|
||||
fetch(APIBaseURL + '/reports/combinedequipmentload?' +
|
||||
|
@ -418,7 +424,44 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
});
|
||||
});
|
||||
setDetailedDataTableColumns(detailed_column_list);
|
||||
|
||||
let associated_equipment_value_list = [];
|
||||
if (json['associated_equipment']['associated_equipment_names_array'].length > 0) {
|
||||
json['associated_equipment']['associated_equipment_names_array'][0].forEach((currentEquipmentName, equipmentIndex) => {
|
||||
let associated_equipment_value = {};
|
||||
associated_equipment_value['id'] = equipmentIndex;
|
||||
associated_equipment_value['name'] = currentEquipmentName;
|
||||
json['associated_equipment']['energy_category_names'].forEach((currentValue, energyCategoryIndex) => {
|
||||
associated_equipment_value['a' + 2 * energyCategoryIndex] = json['associated_equipment']['sub_averages'][energyCategoryIndex][equipmentIndex].toFixed(2);
|
||||
associated_equipment_value['a' + 2 * energyCategoryIndex + 1] = json['associated_equipment']['sub_maximums'][energyCategoryIndex][equipmentIndex].toFixed(2);
|
||||
});
|
||||
associated_equipment_value_list.push(associated_equipment_value);
|
||||
});
|
||||
};
|
||||
|
||||
setAssociatedEquipmentTableData(associated_equipment_value_list);
|
||||
|
||||
let associated_equipment_column_list = [];
|
||||
associated_equipment_column_list.push({
|
||||
dataField: 'name',
|
||||
text: t('Associated Equipment'),
|
||||
sort: true
|
||||
});
|
||||
json['associated_equipment']['energy_category_names'].forEach((currentValue, index) => {
|
||||
let unit = json['associated_equipment']['units'][index];
|
||||
associated_equipment_column_list.push({
|
||||
dataField: 'a' + 2 * index,
|
||||
text: currentValue + ' ' + t('Average Load') + ' (' + unit + '/H)',
|
||||
sort: true
|
||||
});
|
||||
associated_equipment_column_list.push({
|
||||
dataField: 'a' + (2 * index + 1),
|
||||
text: currentValue + ' ' + t('Maximum Load') + ' (' + unit + '/H)',
|
||||
sort: true
|
||||
});
|
||||
});
|
||||
|
||||
setAssociatedEquipmentTableColumns(associated_equipment_column_list);
|
||||
|
||||
setExcelBytesBase64(json['excel_bytes_base64']);
|
||||
|
||||
// enable submit button
|
||||
|
@ -642,6 +685,9 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
<br />
|
||||
<DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} >
|
||||
</DetailedDataTable>
|
||||
<br />
|
||||
<AssociatedEquipmentTable data={associatedEquipmentTableData} title={t('Associated Equipment Data')} columns={associatedEquipmentTableColumns}>
|
||||
</AssociatedEquipmentTable>
|
||||
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -33,6 +33,7 @@ import { comparisonTypeOptions } from '../common/ComparisonTypeOptions';
|
|||
|
||||
|
||||
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
|
||||
const AssociatedEquipmentTable = loadable(() => import('../common/AssociatedEquipmentTable'));
|
||||
|
||||
const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
|
||||
let current_moment = moment();
|
||||
|
@ -87,6 +88,10 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
|
||||
const [detailedDataTableData, setDetailedDataTableData] = useState([]);
|
||||
const [detailedDataTableColumns, setDetailedDataTableColumns] = useState([{dataField: 'startdatetime', text: t('Datetime'), sort: true}]);
|
||||
|
||||
const [associatedEquipmentTableData, setAssociatedEquipmentTableData] = useState([]);
|
||||
const [associatedEquipmentTableColumns, setAssociatedEquipmentTableColumns] = useState([{dataField: 'name', text: t('Associated Equipment'), sort: true }]);
|
||||
|
||||
const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -291,6 +296,7 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
|
||||
// Reinitialize tables
|
||||
setDetailedDataTableData([]);
|
||||
setAssociatedEquipmentTableData([]);
|
||||
|
||||
let isResponseOK = false;
|
||||
fetch(APIBaseURL + '/reports/combinedequipmentstatistics?' +
|
||||
|
@ -416,6 +422,37 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
})
|
||||
});
|
||||
setDetailedDataTableColumns(detailed_column_list);
|
||||
let associated_equipment_value_list = [];
|
||||
if (json['associated_equipment']['associated_equipment_names_array'].length > 0) {
|
||||
json['associated_equipment']['associated_equipment_names_array'][0].forEach((currentEquipmentName, equipmentIndex) => {
|
||||
let associated_equipment_value = {};
|
||||
associated_equipment_value['id'] = equipmentIndex;
|
||||
associated_equipment_value['name'] = currentEquipmentName;
|
||||
json['associated_equipment']['energy_category_names'].forEach((currentValue, energyCategoryIndex) => {
|
||||
associated_equipment_value['a' + energyCategoryIndex] = json['associated_equipment']['subtotals_array'][energyCategoryIndex][equipmentIndex].toFixed(2);
|
||||
});
|
||||
associated_equipment_value_list.push(associated_equipment_value);
|
||||
});
|
||||
};
|
||||
|
||||
setAssociatedEquipmentTableData(associated_equipment_value_list);
|
||||
|
||||
let associated_equipment_column_list = [];
|
||||
associated_equipment_column_list.push({
|
||||
dataField: 'name',
|
||||
text: t('Associated Equipment'),
|
||||
sort: true
|
||||
});
|
||||
json['associated_equipment']['energy_category_names'].forEach((currentValue, index) => {
|
||||
let unit = json['associated_equipment']['units'][index];
|
||||
associated_equipment_column_list.push({
|
||||
dataField: 'a' + index,
|
||||
text: currentValue + ' (' + unit + ')',
|
||||
sort: true
|
||||
});
|
||||
});
|
||||
|
||||
setAssociatedEquipmentTableColumns(associated_equipment_column_list);
|
||||
|
||||
setExcelBytesBase64(json['excel_bytes_base64']);
|
||||
|
||||
|
@ -657,6 +694,9 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
|
|||
<br />
|
||||
<DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} >
|
||||
</DetailedDataTable>
|
||||
<br />
|
||||
<AssociatedEquipmentTable data={associatedEquipmentTableData} title={t('Associated Equipment Data')} columns={associatedEquipmentTableColumns}>
|
||||
</AssociatedEquipmentTable>
|
||||
|
||||
</Fragment>
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue