Merge remote-tracking branch 'origin_myems/develop' into develop

pull/25/head
hyh123a 2021-03-28 19:51:24 +08:00
commit 0f6a6d20c1
17 changed files with 1118 additions and 169 deletions

View File

@ -22,53 +22,43 @@ MyEMS是行业领先的开源能源管理系统利用云计算、物联网、
## MyEMS组件(社区版) ## MyEMS组件(社区版)
MyEMS项目由下列组件构成: MyEMS项目由下列组件构成:
### MyEMS 数据库 ### MyEMS 数据库 (SQL)
SQL
[安装 数据库](./database/README.md) [安装 数据库](./database/README.md)
### MyEMS API 应用程序接口 ### MyEMS API 应用程序接口 (Python)
Python
[安装 myems-api](./myems-api/README.md) [安装 myems-api](./myems-api/README.md)
### MyEMS 管理 UI ### MyEMS 管理 UI (AngularJS)
AngularJS
[安装 admin UI](./admin/README.md) [安装 admin UI](./admin/README.md)
### MyEMS BACnet/IP 数据采集服务 ### MyEMS BACnet/IP 数据采集服务 (Python)
Python
[安装 myems-bacnet](./myems-bacnet/README.md) [安装 myems-bacnet](./myems-bacnet/README.md)
### MyEMS Modbus TCP 数据采集服务 ### MyEMS Modbus TCP 数据采集服务 (Python)
Python
[安装 myems-modbus-tcp](./myems-modbus-tcp/README.md) [安装 myems-modbus-tcp](./myems-modbus-tcp/README.md)
### MyEMS MQTT数据转发服务 ### MyEMS MQTT数据转发服务 (Python)
Python
[安装 myems-mqtt-publisher](./myems-mqtt-publisher/README.md) [安装 myems-mqtt-publisher](./myems-mqtt-publisher/README.md)
### MyEMS 数据清洗服务 ### MyEMS 数据清洗服务 (Python)
Python
[安装 myems-cleaning](./myems-cleaning/README.md) [安装 myems-cleaning](./myems-cleaning/README.md)
### MyEMS 数据规范化服务 ### MyEMS 数据规范化服务 (Python)
Python
[安装 myems-normalization](./myems-normalization/README.md) [安装 myems-normalization](./myems-normalization/README.md)
### MyEMS 数据汇总服务 ### MyEMS 数据汇总服务 (Python)
Python
[安装 myems-aggregation](./myems-aggregation/README.md) [安装 myems-aggregation](./myems-aggregation/README.md)
### MyEMS Web UI ### MyEMS Web UI (ReactJS)
ReactJS
[安装 web UI](./web/README.md) [安装 web UI](./web/README.md)

View File

@ -23,53 +23,43 @@ MyEMS wird von einem erfahrenen Entwicklungsteam entwickelt und gewartet, und de
Dieses Projekt besteht aus folgenden Komponenten: Dieses Projekt besteht aus folgenden Komponenten:
### MyEMS Database ### MyEMS Database (SQL)
SQL
[Installieren database](./database/README.md) [Installieren database](./database/README.md)
### MyEMS API ### MyEMS API (Python)
Python
[Installieren myems-api](./myems-api/README.md) [Installieren myems-api](./myems-api/README.md)
### MyEMS Admin UI ### MyEMS Admin UI (AngularJS)
AngularJS
[Installieren admin UI](./admin/README.md) [Installieren admin UI](./admin/README.md)
### MyEMS BACnet/IP Acquisition Service ### MyEMS BACnet/IP Acquisition Service (Python)
Python
[Installieren myems-bacnet](./myems-bacnet/README.md) [Installieren myems-bacnet](./myems-bacnet/README.md)
### MyEMS Modbus TCP Acquisition Service ### MyEMS Modbus TCP Acquisition Service (Python)
Python
[Installieren myems-modbus-tcp](./myems-modbus-tcp/README.md) [Installieren myems-modbus-tcp](./myems-modbus-tcp/README.md)
### MyEMS MQTT Data vorwärts Service ### MyEMS MQTT Data vorwärts Service (Python)
Python
[Installieren myems-mqtt-publisher](./myems-mqtt-publisher/README.md) [Installieren myems-mqtt-publisher](./myems-mqtt-publisher/README.md)
### MyEMS Cleaning Service ### MyEMS Cleaning Service (Python)
Python
[Installieren myems-cleaning](./myems-cleaning/README.md) [Installieren myems-cleaning](./myems-cleaning/README.md)
### MyEMS Normalization Service ### MyEMS Normalization Service (Python)
Python
[Installieren myems-normalization](./myems-normalization/README.md) [Installieren myems-normalization](./myems-normalization/README.md)
### MyEMS Aggregation Service ### MyEMS Aggregation Service (Python)
Python
[Installieren myems-aggregation](./myems-aggregation/README.md) [Installieren myems-aggregation](./myems-aggregation/README.md)
### MyEMS Web UI ### MyEMS Web UI (ReactJS)
ReactJS
[Installieren web UI](./web/README.md) [Installieren web UI](./web/README.md)

View File

@ -23,53 +23,43 @@ MyEMS is being developed and maintained by an experienced development team, and
This project is compose of following components: This project is compose of following components:
### MyEMS Database ### MyEMS Database (SQL)
SQL
[Install database](./database/README.md) [Install database](./database/README.md)
### MyEMS API ### MyEMS API (Python)
Python
[Install myems-api](./myems-api/README.md) [Install myems-api](./myems-api/README.md)
### MyEMS Admin UI ### MyEMS Admin UI (ReactJS)
ReactJS
[Install admin UI](./admin/README.md) [Install admin UI](./admin/README.md)
### MyEMS BACnet/IP Acquisition Service ### MyEMS BACnet/IP Acquisition Service (Python)
Python
[Install myems-bacnet](./myems-bacnet/README.md) [Install myems-bacnet](./myems-bacnet/README.md)
### MyEMS Modbus TCP Acquisition Service ### MyEMS Modbus TCP Acquisition Service (Python)
Python
[Install myems-modbus-tcp](./myems-modbus-tcp/README.md) [Install myems-modbus-tcp](./myems-modbus-tcp/README.md)
### MyEMS MQTT Data Forwarding Service ### MyEMS MQTT Data Forwarding Service (Python)
Python
[Install myems-mqtt-publisher](./myems-mqtt-publisher/README.md) [Install myems-mqtt-publisher](./myems-mqtt-publisher/README.md)
### MyEMS Cleaning Service ### MyEMS Cleaning Service (Python)
Python
[Install myems-cleaning](./myems-cleaning/README.md) [Install myems-cleaning](./myems-cleaning/README.md)
### MyEMS Normalization Service ### MyEMS Normalization Service (Python)
Python
[Install myems-normalization](./myems-normalization/README.md) [Install myems-normalization](./myems-normalization/README.md)
### MyEMS Aggregation Service ### MyEMS Aggregation Service (Python)
Python
[Install myems-aggregation](./myems-aggregation/README.md) [Install myems-aggregation](./myems-aggregation/README.md)
### MyEMS Web UI ### MyEMS Web UI (AngularJS)
AngularJS
[Install web UI](./web/README.md) [Install web UI](./web/README.md)

View File

@ -84,6 +84,24 @@ CREATE TABLE IF NOT EXISTS `myems_fdd_db`.`tbl_rules` (
PRIMARY KEY (`id`)); PRIMARY KEY (`id`));
CREATE INDEX `tbl_rules_index_1` ON `myems_fdd_db`.`tbl_rules` (`name`); 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 (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); 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);

View File

@ -16,6 +16,12 @@ import statistics
######################################################################################################################## ########################################################################################################################
def aggregate_hourly_data_by_period(rows_hourly, start_datetime_utc, end_datetime_utc, period_type): def aggregate_hourly_data_by_period(rows_hourly, start_datetime_utc, end_datetime_utc, period_type):
# todo: validate parameters # 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) start_datetime_utc = start_datetime_utc.replace(tzinfo=None)
end_datetime_utc = end_datetime_utc.replace(tzinfo=None) end_datetime_utc = end_datetime_utc.replace(tzinfo=None)

View File

@ -484,17 +484,19 @@ def generate_excel(report,
parameters_ws_current_row_number += 1 parameters_ws_current_row_number += 1
table_current_col_number = 'B' table_current_col_number = 2
for i in range(0, parameters_names_len): for i in range(0, parameters_names_len):
if len(parameters_data['timestamps'][i]) == 0: if len(parameters_data['timestamps'][i]) == 0:
continue continue
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].fill = table_fill col = format_cell.get_column_letter(table_current_col_number)
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
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)].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)].border = f_border
@ -505,14 +507,14 @@ def generate_excel(report,
table_current_row_number = parameters_ws_current_row_number table_current_row_number = parameters_ws_current_row_number
for j, value in enumerate(list(parameters_data['timestamps'][i])): 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)].border = f_border
parameters_ws[col + str(table_current_row_number)].font = title_font 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)].alignment = c_c_alignment
parameters_ws[col + str(table_current_row_number)] = value 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)].border = f_border
parameters_ws[col + str(table_current_row_number)].font = title_font 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_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 # parameters chart and parameters table

View File

@ -4,7 +4,6 @@ import os
from openpyxl.chart import ( from openpyxl.chart import (
PieChart, PieChart,
LineChart, LineChart,
BarChart,
Reference, Reference,
) )
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
@ -432,6 +431,63 @@ def generate_excel(report,
chart_start_row_number += 6 chart_start_row_number += 6
ws.add_chart(line, chart_cell) 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' filename = str(uuid.uuid4()) + '.xlsx'
wb.save(filename) wb.save(filename)

View File

@ -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

View File

@ -484,35 +484,37 @@ def generate_excel(report,
parameters_ws_current_row_number += 1 parameters_ws_current_row_number += 1
table_current_col_number = 'B' table_current_col_number = 2
for i in range(0, parameters_names_len): for i in range(0, parameters_names_len):
if len(parameters_data['timestamps'][i]) == 0: if len(parameters_data['timestamps'][i]) == 0:
continue continue
parameters_ws[table_current_col_number + str(parameters_ws_current_row_number-1)].fill = table_fill col = format_cell.get_column_letter(table_current_col_number)
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)].fill = table_fill col = format_cell.get_column_letter(table_current_col_number + 1)
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)].fill = table_fill
parameters_ws[col + str(parameters_ws_current_row_number-1)].alignment = c_c_alignment parameters_ws[col + str(parameters_ws_current_row_number - 1)].border = f_border
parameters_ws[col + str(parameters_ws_current_row_number-1)] = parameters_data['names'][i] 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 table_current_row_number = parameters_ws_current_row_number
for j, value in enumerate(list(parameters_data['timestamps'][i])): 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)].border = f_border
parameters_ws[col + str(table_current_row_number)].font = title_font 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)].alignment = c_c_alignment
parameters_ws[col + str(table_current_row_number)] = value 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)].border = f_border
parameters_ws[col + str(table_current_row_number)].font = title_font 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_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 # parameters chart and parameters table

View File

@ -23,11 +23,13 @@ class Reporting:
# Step 2: query the combined equipment # Step 2: query the combined equipment
# Step 3: query energy items # Step 3: query energy items
# Step 4: query associated points # Step 4: query associated points
# Step 5: query base period energy input # Step 5: query associated equipments
# Step 6: query reporting period energy input # Step 6: query base period energy input
# Step 7: query tariff data # Step 7: query reporting period energy input
# Step 8: query associated points data # Step 8: query tariff data
# Step 9: construct the report # Step 9: query associated points data
# Step 10: query associated equipments energy input
# Step 11: construct the report
#################################################################################################################### ####################################################################################################################
@staticmethod @staticmethod
def on_get(req, resp): 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]}) 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() base = dict()
if energy_item_set is not None and len(energy_item_set) > 0: 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 base[energy_item_id]['subtotal'] += actual_value
################################################################################################################ ################################################################################################################
# Step 6: query reporting period energy input # Step 7: query reporting period energy input
################################################################################################################ ################################################################################################################
reporting = dict() reporting = dict()
if energy_item_set is not None and len(energy_item_set) > 0: 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] reporting[energy_item_id]['offpeak'] += row[1]
################################################################################################################ ################################################################################################################
# Step 7: query tariff data # Step 8: query tariff data
################################################################################################################ ################################################################################################################
parameters_data = dict() parameters_data = dict()
parameters_data['names'] = list() parameters_data['names'] = list()
@ -379,7 +395,7 @@ class Reporting:
parameters_data['values'].append(tariff_value_list) parameters_data['values'].append(tariff_value_list)
################################################################################################################ ################################################################################################################
# Step 8: query associated points data # Step 9: query associated points data
################################################################################################################ ################################################################################################################
for point in point_list: for point in point_list:
point_values = [] point_values = []
@ -444,7 +460,37 @@ class Reporting:
parameters_data['values'].append(point_values) 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: if cursor_system:
cursor_system.close() cursor_system.close()
@ -522,6 +568,20 @@ class Reporting:
"values": parameters_data['values'] "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 # export result to Excel file and then encode the file to base64 string
result['excel_bytes_base64'] = excelexporters.combinedequipmentenergyitem.export(result, result['excel_bytes_base64'] = excelexporters.combinedequipmentenergyitem.export(result,
combined_equipment['name'], combined_equipment['name'],

View File

@ -5,6 +5,7 @@ import config
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from core import utilities from core import utilities
from decimal import Decimal from decimal import Decimal
import excelexporters.equipmentcost
class Reporting: class Reporting:
@ -511,5 +512,9 @@ class Reporting:
"timestamps": parameters_data['timestamps'], "timestamps": parameters_data['timestamps'],
"values": parameters_data['values'] "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) resp.body = json.dumps(result)

View File

@ -7,30 +7,32 @@ import schedule
def job(logger): def job(logger):
cnx = None cnx_historical = None
cursor = None cursor_historical = None
try: try:
cnx = mysql.connector.connect(**config.myems_historical_db) cnx_historical = mysql.connector.connect(**config.myems_historical_db)
cursor = cnx.cursor() cursor_historical = cnx_historical.cursor()
except Exception as e: except Exception as e:
logger.error("Error in clean analog value process " + str(e)) logger.error("Error in clean analog value process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
return return
expired_utc = datetime.utcnow() - timedelta(days=config.live_in_days) expired_utc = datetime.utcnow() - timedelta(days=config.live_in_days)
try: try:
cursor.execute(" DELETE FROM tbl_analog_value WHERE utc_date_time < %s ", (expired_utc,)) cursor_historical.execute(" DELETE "
cnx.commit() " FROM tbl_analog_value "
" WHERE utc_date_time < %s ", (expired_utc,))
cnx_historical.commit()
except Exception as e: except Exception as e:
logger.error("Error in delete_expired_trend process " + str(e)) logger.error("Error in delete_expired_trend process " + str(e))
finally: finally:
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
logger.info("Deleted trend before date time in UTC: " + expired_utc.isoformat()[0:19]) logger.info("Deleted trend before date time in UTC: " + expired_utc.isoformat()[0:19])

View File

@ -7,30 +7,32 @@ import schedule
def job(logger): def job(logger):
cnx = None cnx_historical = None
cursor = None cursor_historical = None
try: try:
cnx = mysql.connector.connect(**config.myems_historical_db) cnx_historical = mysql.connector.connect(**config.myems_historical_db)
cursor = cnx.cursor() cursor_historical = cnx_historical.cursor()
except Exception as e: except Exception as e:
logger.error("Error in clean digital value process " + str(e)) logger.error("Error in clean digital value process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
return return
expired_utc = datetime.utcnow() - timedelta(days=config.live_in_days) expired_utc = datetime.utcnow() - timedelta(days=config.live_in_days)
try: try:
cursor.execute(" DELETE FROM tbl_digital_value WHERE utc_date_time < %s ", (expired_utc,)) cursor_historical.execute(" DELETE "
cnx.commit() " FROM tbl_digital_value "
" WHERE utc_date_time < %s ", (expired_utc,))
cnx_historical.commit()
except Exception as e: except Exception as e:
logger.error("Error in delete_expired_trend process " + str(e)) logger.error("Error in delete_expired_trend process " + str(e))
finally: finally:
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
logger.info("Deleted trend before date time in UTC: " + expired_utc.isoformat()[0:19]) logger.info("Deleted trend before date time in UTC: " + expired_utc.isoformat()[0:19])

View File

@ -1,7 +1,7 @@
import mysql.connector import mysql.connector
import config import config
import time import time
from datetime import datetime from datetime import datetime, timedelta
######################################################################################################################## ########################################################################################################################
@ -17,17 +17,17 @@ def process(logger):
while True: while True:
# the outermost loop to reconnect server if there is a connection error # the outermost loop to reconnect server if there is a connection error
cnx = None cnx_historical = None
cursor = None cursor_historical = None
try: try:
cnx = mysql.connector.connect(**config.myems_historical_db) cnx_historical = mysql.connector.connect(**config.myems_historical_db)
cursor = cnx.cursor() cursor_historical = cnx_historical.cursor()
except Exception as e: except Exception as e:
logger.error("Error at the begin of clean_energy_value.process " + str(e)) logger.error("Error at the begin of clean_energy_value.process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
time.sleep(60) time.sleep(60)
continue continue
@ -46,19 +46,20 @@ def process(logger):
query = (" SELECT MIN(utc_date_time), MAX(utc_date_time) " query = (" SELECT MIN(utc_date_time), MAX(utc_date_time) "
" FROM tbl_energy_value " " FROM tbl_energy_value "
" WHERE is_bad IS NULL ") " WHERE is_bad IS NULL ")
cursor.execute(query, ()) cursor_historical.execute(query, ())
row_datetime = cursor.fetchone() row_datetime = cursor_historical.fetchone()
if row_datetime is not None and len(row_datetime) == 2 and \ if row_datetime is not None and len(row_datetime) == 2 and \
isinstance(row_datetime[0], datetime) and isinstance(row_datetime[1], datetime): 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] max_datetime = row_datetime[1]
except Exception as e: except Exception as e:
logger.error("Error in Step 1 of clean_energy_value.process " + str(e)) logger.error("Error in Step 1 of clean_energy_value.process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
time.sleep(60) time.sleep(60)
continue continue
print("min_datetime: " + min_datetime.isoformat()[0:19]) 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 # 3333 2018-02-08 00:54:16 165599.015625 good
################################################################################################################ ################################################################################################################
print("Step 2: Processing bad case 1.x") print("Step 2: Processing bad case 1.x")
cnx_system = None
cursor_system = None
try: try:
cnx_system = mysql.connector.connect(**config.myems_system_db) cnx_system = mysql.connector.connect(**config.myems_system_db)
cursor_system = cnx_system.cursor(dictionary=True) cursor_system = cnx_system.cursor(dictionary=True)
@ -193,23 +196,24 @@ def process(logger):
if cursor_system: if cursor_system:
cursor_system.close() cursor_system.close()
if cnx_system: if cnx_system:
cnx_system.close() cnx_system.disconnect()
try: try:
query = (" SELECT id, point_id, actual_value " query = (" SELECT id, point_id, actual_value "
" FROM tbl_energy_value " " FROM tbl_energy_value "
" WHERE utc_date_time >= %s AND utc_date_time <= %s AND is_bad IS NOT TRUE ") " WHERE utc_date_time >= %s AND utc_date_time <= %s AND is_bad IS NOT TRUE ")
cursor.execute(query, (min_datetime, max_datetime,)) cursor_historical.execute(query, (min_datetime, max_datetime,))
rows_energy_values = cursor.fetchall() rows_energy_values = cursor_historical.fetchall()
except Exception as e: except Exception as e:
logger.error("Error in step 2.2 of clean_energy_value.process " + str(e)) logger.error("Error in step 2.2 of clean_energy_value.process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
time.sleep(60) time.sleep(60)
continue continue
# initialize bad list
bad_list = list() bad_list = list()
if rows_energy_values is not None and len(rows_energy_values) > 0: 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 " update = (" UPDATE tbl_energy_value "
" SET is_bad = TRUE " " SET is_bad = TRUE "
" WHERE id IN (" + ', '.join(map(str, bad_list)) + ")") " WHERE id IN (" + ', '.join(map(str, bad_list)) + ")")
cursor.execute(update, ) cursor_historical.execute(update, )
cnx.commit() cnx_historical.commit()
except Exception as e: except Exception as e:
logger.error("Error in step 2.3 of clean_energy_value.process " + str(e)) logger.error("Error in step 2.3 of clean_energy_value.process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
time.sleep(60) time.sleep(60)
continue continue
@ -380,14 +384,14 @@ def process(logger):
" FROM tbl_energy_value " " FROM tbl_energy_value "
" WHERE utc_date_time >= %s AND utc_date_time <= %s AND is_bad IS NOT TRUE " " WHERE utc_date_time >= %s AND utc_date_time <= %s AND is_bad IS NOT TRUE "
" ORDER BY point_id, utc_date_time ") " ORDER BY point_id, utc_date_time ")
cursor.execute(query, (min_datetime, max_datetime,)) cursor_historical.execute(query, (min_datetime, max_datetime,))
rows_energy_values = cursor.fetchall() rows_energy_values = cursor_historical.fetchall()
except Exception as e: except Exception as e:
logger.error("Error in step 3.1 of clean_energy_value.process " + str(e)) logger.error("Error in step 3.1 of clean_energy_value.process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
time.sleep(60) time.sleep(60)
continue continue
@ -416,6 +420,7 @@ def process(logger):
if len(current_point_value_list) > 0: if len(current_point_value_list) > 0:
point_value_dict[current_point_id] = current_point_value_list point_value_dict[current_point_id] = current_point_value_list
# reinitialize bad list
bad_list = list() bad_list = list()
for point_id, point_value_list in point_value_dict.items(): for point_id, point_value_list in point_value_dict.items():
@ -449,14 +454,14 @@ def process(logger):
update = (" UPDATE tbl_energy_value " update = (" UPDATE tbl_energy_value "
" SET is_bad = TRUE " " SET is_bad = TRUE "
" WHERE id IN (" + ', '.join(map(str, bad_list)) + ")") " WHERE id IN (" + ', '.join(map(str, bad_list)) + ")")
cursor.execute(update, ) cursor_historical.execute(update, )
cnx.commit() cnx_historical.commit()
except Exception as e: except Exception as e:
logger.error("Error in step 3.2 of clean_energy_value.process " + str(e)) logger.error("Error in step 3.2 of clean_energy_value.process " + str(e))
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
time.sleep(60) time.sleep(60)
continue continue
@ -544,16 +549,16 @@ def process(logger):
" SET is_bad = FALSE " " SET is_bad = FALSE "
" WHERE utc_date_time >= %s AND utc_date_time < %s AND is_bad IS NULL ") " 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 # NOTE: use '<' instead of '<=' in WHERE statement because there may be some new inserted values
cursor.execute(update, (min_datetime, max_datetime,)) cursor_historical.execute(update, (min_datetime, max_datetime,))
cnx.commit() cnx_historical.commit()
except Exception as e: except Exception as e:
logger.error("Error in step 4 of clean_energy_value.process " + str(e)) logger.error("Error in step 4 of clean_energy_value.process " + str(e))
time.sleep(60) time.sleep(60)
continue continue
finally: finally:
if cursor: if cursor_historical:
cursor.close() cursor_historical.close()
if cnx: if cnx_historical:
cnx.close() cnx_historical.disconnect()
time.sleep(900) time.sleep(900)

View File

@ -1,4 +1,3 @@
# definition of the database
myems_system_db = { myems_system_db = {
'user': 'root', 'user': 'root',
'password': '!MyEMS1', 'password': '!MyEMS1',
@ -18,7 +17,8 @@ myems_historical_db = {
# indicates how long analog values and digital values will be kept in database # indicates how long analog values and digital values will be kept in database
# the longer days the more memory and disc space needed. # the longer days the more memory and disc space needed.
live_in_days = 365 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 # indicates if the program is in debug mode
is_debug = False is_debug = False

View File

@ -33,6 +33,7 @@ import { comparisonTypeOptions } from '../common/ComparisonTypeOptions';
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable')); const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
const AssociatedEquipmentTable = loadable(() => import('../common/AssociatedEquipmentTable'));
const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => { const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
let current_moment = moment(); let current_moment = moment();
@ -87,6 +88,10 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
const [detailedDataTableData, setDetailedDataTableData] = useState([]); const [detailedDataTableData, setDetailedDataTableData] = useState([]);
const [detailedDataTableColumns, setDetailedDataTableColumns] = useState([{dataField: 'startdatetime', text: t('Datetime'), sort: true}]); 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); const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
useEffect(() => { useEffect(() => {
@ -291,6 +296,7 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
// Reinitialize tables // Reinitialize tables
setDetailedDataTableData([]); setDetailedDataTableData([]);
setAssociatedEquipmentTableData([]);
let isResponseOK = false; let isResponseOK = false;
fetch(APIBaseURL + '/reports/combinedequipmentload?' + fetch(APIBaseURL + '/reports/combinedequipmentload?' +
@ -418,6 +424,43 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
}); });
}); });
setDetailedDataTableColumns(detailed_column_list); 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']); setExcelBytesBase64(json['excel_bytes_base64']);
@ -642,6 +685,9 @@ const CombinedEquipmentLoad = ({ setRedirect, setRedirectUrl, t }) => {
<br /> <br />
<DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} > <DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} >
</DetailedDataTable> </DetailedDataTable>
<br />
<AssociatedEquipmentTable data={associatedEquipmentTableData} title={t('Associated Equipment Data')} columns={associatedEquipmentTableColumns}>
</AssociatedEquipmentTable>
</Fragment> </Fragment>
); );

View File

@ -33,6 +33,7 @@ import { comparisonTypeOptions } from '../common/ComparisonTypeOptions';
const DetailedDataTable = loadable(() => import('../common/DetailedDataTable')); const DetailedDataTable = loadable(() => import('../common/DetailedDataTable'));
const AssociatedEquipmentTable = loadable(() => import('../common/AssociatedEquipmentTable'));
const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => { const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
let current_moment = moment(); let current_moment = moment();
@ -87,6 +88,10 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
const [detailedDataTableData, setDetailedDataTableData] = useState([]); const [detailedDataTableData, setDetailedDataTableData] = useState([]);
const [detailedDataTableColumns, setDetailedDataTableColumns] = useState([{dataField: 'startdatetime', text: t('Datetime'), sort: true}]); 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); const [excelBytesBase64, setExcelBytesBase64] = useState(undefined);
useEffect(() => { useEffect(() => {
@ -291,6 +296,7 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
// Reinitialize tables // Reinitialize tables
setDetailedDataTableData([]); setDetailedDataTableData([]);
setAssociatedEquipmentTableData([]);
let isResponseOK = false; let isResponseOK = false;
fetch(APIBaseURL + '/reports/combinedequipmentstatistics?' + fetch(APIBaseURL + '/reports/combinedequipmentstatistics?' +
@ -416,6 +422,37 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
}) })
}); });
setDetailedDataTableColumns(detailed_column_list); 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']); setExcelBytesBase64(json['excel_bytes_base64']);
@ -657,6 +694,9 @@ const CombinedEquipmentStatistics = ({ setRedirect, setRedirectUrl, t }) => {
<br /> <br />
<DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} > <DetailedDataTable data={detailedDataTableData} title={t('Detailed Data')} columns={detailedDataTableColumns} pagesize={50} >
</DetailedDataTable> </DetailedDataTable>
<br />
<AssociatedEquipmentTable data={associatedEquipmentTableData} title={t('Associated Equipment Data')} columns={associatedEquipmentTableColumns}>
</AssociatedEquipmentTable>
</Fragment> </Fragment>
); );