积累修改;

This commit is contained in:
何 泽隆
2024-12-12 22:02:09 +08:00
parent 38d6ff30a3
commit 810bac464f
12 changed files with 599 additions and 234 deletions

View File

@@ -1,33 +1,36 @@
import time
import datetime
import requests
import numpy as np
import pandas as pd
from pathlib import Path
from bs4 import BeautifulSoup
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from sqlalchemy import create_engine
from sqlalchemy import MetaData, Table, Column, String, Float, Integer
API_URL = "https://energy-iot.chinatowercom.cn/api/device/device/historyPerformance"
headers = {
"Accept-Encoding": "gzip, deflate, br, zstd",
"Connection": "keep-alive",
"Content-Length": "211",
"Cookie": "HWWAFSESTIME=1732173820506; HWWAFSESID=1739685743c73769ff; dc04ed2361044be8a9355f6efb378cf2=WyIzNTI0NjE3OTgzIl0",
"Host": "energy-iot.chinatowercom.cn",
"Origin": "https://energy-iot.chinatowercom.cn",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0",
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiIl0sInVzZXJfbmFtZSI6IndlYl9tYW5hZ2V8d2FuZ2xlaTQiLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNzMyMjc4NDA5LCJ1c2VySWQiOjI0Mjg1LCJqdGkiOiJkODE0YTZhYy05YmJmLTQ0ZjQtYWRhYi0wMzAzNjUzNmNhNWIiLCJjbGllbnRfaWQiOiJ3ZWJfbWFuYWdlIn0.VhJaDKwzjekwOCsw_jOF_jvg7sX45okFcxkLyWtbfFVGWVWANhKNhVqj5Dn0Qb3wUXH3e-w74sDN1RI9QADngMOGP_H7aTwI_nukj6VmjpFA7kEtOBwa6ouvPZQMa1qa3UWl21Ac6GoLu14T4TIf4kQAMTdaYAMFrwDAXAkqvIDmKKjZbnDFUjUIcj-J_Y-LfHCEBjtcz7Rp_wMO-PMA5wII6kbcNoSFiYb0djcFQyeBcIUSUTRPixPcTYBkS-IhNrsOePIWlpNYMHbPxZdrZkV4M65BmBn4A9MUjWYHm7iIut8WVMdCXR4Sxp9m0mJHXR_IPWES4O7aBcuMkOmjyw",
"content-type": "application/json;charset=UTF-8",
"sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "Windows",
API_HEADER = {
"Accept-Encoding": "gzip, deflate, br, zstd",
"Connection": "keep-alive",
"Content-Length": "170",
"Cookie": "HWWAFSESTIME=1732496660747; HWWAFSESID=880ee8eff3a2d23536; dc04ed2361044be8a9355f6efb378cf2=WyIzNTI0NjE3OTgzIl0",
"authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiIl0sInVzZXJfbmFtZSI6IndlYl9tYW5hZ2V8d2FuZ2xlaTQiLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNzMyNTQ4Nzc5LCJ1c2VySWQiOjI0Mjg1LCJqdGkiOiI1Y2I3ZDA2ZC1hNzczLTQ5ZDQtYmRiMy05ZjdiOWNmMjY3ZTYiLCJjbGllbnRfaWQiOiJ3ZWJfbWFuYWdlIn0.Gpk9eYc3W4gcGLTG4aLSEL7E-VD-qPYsELcyyPuZ29e9STfa18WNcbosdIDulbH-5LDqY6i6aFAWpVm41bIgwzLZpAhlp2dthJcoBn9a90wWO4nz-Xi-MK9MVhNR0C28fyxv7h8jP_LRQkBi-pAzm2j65gkSTL3Vakky6znawZ5pY42U74lF-SnYdGyNFK3Ryy3xeMG4N1Pu_OJFdjXdGANUJZcXg1gh8WrERPo2SvuiCzOVTuUQZO7lRc8qGyILTKC-snz5CoonHaCWMaRzcV5VtCGd-yBncpyMQN9rGPqCiiLmuyTG29aZh5UfR_mloGCQHacqRmYSq3uGkPodBg",
"Host": "energy-iot.chinatowercom.cn",
"Origin": "https://energy-iot.chinatowercom.cn",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0",
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/json;charset=UTF-8",
"sec-ch-ua": "\"Microsoft Edge\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "Windows",
}
SemaMap = {
@@ -39,73 +42,148 @@ SemaMap = {
'apt_power_out': ('0305122001', 'adapter', "输出功率"),
}
def get_history_data(device_id, data_type, times: tuple[int, int]):
""" 读取信号量历史数据, 返回接口json数据 """
body = {
"startTimestamp": times[0],
"endTimestamp": times[1],
"deviceCode": f"{device_id}",
"mid": f"{data_type}",
"businessType": "7",
"pageNum": 2,
"pageSize": 5,
"total": 0
}
req = requests.post(API_URL, data=body, headers=headers)
return req.json()
class Lamina_Data(object):
""" 叠光主站数据分析 """
def __init__(self, database="sqlite:///:memory", header=None):
""" 初始化 """
self.engine = create_engine(database)
def adapter_status_graphs(device_id, times: tuple[int, int]):
""" 获取数据, 绘制图表 """
data_volt_in = get_history_data(device_id, SemaMap["apt_volt_in"], times)
data_curr_in = get_history_data(device_id, SemaMap["apt_curr_in"], times)
data_volt_out = get_history_data(device_id, SemaMap["apt_volt_out"], times)
data_power_out = get_history_data(device_id, SemaMap["apt_power_out"], times)
metadata = MetaData()
metadata.reflect(bind=self.engine)
if 'history' not in metadata.tables:
history_table = Table(
'history', metadata,
Column('dev', String(50)),
Column('mid', String(50)),
Column('time', Integer),
Column('value', Float)
)
metadata.create_all(self.engine)
data_apt = []
for item in zip(data_volt_in['data'], data_volt_out['data'], data_curr_in['data'], data_power_out['data']):
print(item)
piont_time = time.mktime(time.strptime(item[0]['collectTime'], r"%Y-%m-%d %H:%M:%S"))
point_apt = {
'time': int(piont_time),
'volt_in': item[0]['value'],
'volt_out': item[1]['value'],
'curr_in': item[2]['value'],
'power_out': item[3]['value'],
self.data = {
'history': pd.read_sql_table('history', self.engine),
}
data_apt.append(point_apt)
table_apt = pd.DataFrame(data_apt)
# 图表绘制
chart_apt(table_apt)
self.api_origin = {
'domain': 'https://energy-iot.chinatowercom.cn/api',
'header': API_HEADER,
}
def chart_apt(table_apt):
""" 绘制适配器信息图表 """
fig, ax1 = plt.subplots(figsize=(12, 6))
ax1.plot(table_apt['time'], table_apt['volt_in'], color='green', label='Input Voltage')
ax1.plot(table_apt['time'], table_apt['volt_out'], color='red', label='Output Voltage')
# ax1.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d %H:%M:%S'))
def save_history_data(self):
""" 保存历史数据 """
# 设置x轴的主要刻度定位器为自动日期定位器这使得x轴上的刻度根据数据自动选择最合适的日期格式
ax1.xaxis.set_major_locator(mdates.AutoDateLocator())
data_memory = self.data['history']
data_file = pd.read_sql_table('history', self.engine)
ax2 = ax1.twinx()
# 绘制斜线阴影
for i in range(len(table_apt) - 1):
ax1.fill_between(
[table_apt['time'].iloc[i], table_apt['time'].iloc[i + 1]],
[table_apt['power_out'].iloc[i], table_apt['power_out'].iloc[i + 1]],
color='red', alpha=0.5)
# 合并新数据和现有数据
combined_df = pd.concat([data_file, data_memory], ignore_index=True)
# 通过 'dev', 'mid', 'time' 三列进行去重
combined_df.drop_duplicates(subset=['dev', 'mid', 'time'], inplace=True)
# 将去重后的数据插入数据库
combined_df.to_sql('history', self.engine, if_exists='replace', index=False)
lines, labels = ax1.get_legend_handles_labels()
shadows, shadow_labels = ax2.get_legend_handles_labels()
ax1.legend(lines + shadows, labels + shadow_labels, loc='upper left')
print(f"成功插入 {len(combined_df)} 条数据")
ax1.set_title('Device Data Visualization')
ax1.set_xlabel('Time')
ax1.set_ylabel('Voltage (V)')
ax2.set_ylabel('Power (W)')
return len(combined_df)
plt.show()
def get_histoty_data(self, device_id, data_type, time_start:int, time_end:int):
""" 读取历史数据 """
flag = 0
time_Interval = 20 * 60
database = self.data['history']
filter_data = database[database['dev'] == device_id &
database['mid'] == SemaMap[data_type][0] &
database['time'].between(time_start, time_end)]
if filter_data.shape[1] == 0 or (filter_data['time'].min() - time_start > time_Interval) or (time_end - filter_data['time'].max() > time_Interval):
""" 需要从网页获取数据 """
flag = 1
return filter_data
def get_history_data_by_net(self, device_id, data_type, time_start:int, time_end:int, header=None):
""" 读取信号量历史数据, 返回接口json数据 """
if header is None:
header = self.api_origin['header']
body = {
"businessType": "7",
"startTimestamp": int(time_start * 1000),
"endTimestamp": int(time_end * 1000),
"deviceCode": f"{device_id}",
"mid": f"{data_type[0]}",
"pageNum": 1,
"pageSize": 10,
"total": 0
}
req = requests.post(API_URL, json=body, headers=header)
json_data = req.json()
if json_data['code'] == 200:
""" 数据读取成功 """
print(f"Get data success, len={len(json_data['data'])}")
table_data = pd.DataFrame(json_data['data'], columns=['collectTime', 'mid', 'midName', 'value'])
table_data['time'] = table_data['collectTime'].apply(lambda x: int(time.mktime(time.strptime(x, r"%Y-%m-%d %H:%M:%S"))))
table_data['dev'] = device_id
return table_data[['dev', 'mid', 'time', 'value']]
else:
print(f"Get data fail, code={json_data['code']}, msg=\n\t{json_data['msg']}")
return pd.DataFrame([], columns=['dev', 'mid', 'time', 'value'])
def graphs_adapter(self, device_id, time_start:int|str, time_end:int|str):
""" 绘制图表-适配器数据 """
if type(time_start) is str:
time_start = time.mktime(time.strptime(time_start, r"%Y-%m-%d %H:%M:%S"))
if type(time_end) is str:
time_end = time.mktime(time.strptime(time_end, r"%Y-%m-%d %H:%M:%S"))
data_volt_in = self.get_history_data_by_net(device_id, SemaMap["apt_volt_in"], time_start, time_end)
data_curr_in = self.get_history_data_by_net(device_id, SemaMap["apt_curr_in"], time_start, time_end)
data_volt_out = self.get_history_data_by_net(device_id, SemaMap["apt_volt_out"], time_start, time_end)
data_power_out = self.get_history_data_by_net(device_id, SemaMap["apt_power_out"], time_start, time_end)
combined_df = pd.concat([data_volt_in, data_curr_in, data_volt_out, data_power_out], ignore_index=True)
self.data['history'] = pd.concat([self.data['history'], combined_df], ignore_index=True)
self.save_history_data()
data_adapter = pd.DataFrame([], columns=['time', 'volt_in', 'volt_out', 'curr_in', 'power_out'])
data_adapter.time = data_volt_in.time
data_adapter.volt_in = data_volt_in.value
data_adapter.volt_out = data_volt_out.value
data_adapter.curr_in = data_curr_in.value
data_adapter.power_out = data_power_out.value
return data_adapter
def chart_adapter(self, data_adapter):
""" 绘制适配器信息图表 """
fig, ax1 = plt.subplots()
ax1.plot(data_adapter['time'], data_adapter['volt_in'], color='green', label='Input Voltage')
ax1.plot(data_adapter['time'], data_adapter['volt_out'], color='red', label='Output Voltage')
ax2 = ax1.twinx()
ax2.plot(data_adapter['time'], data_adapter['power_out'], color='gray', label='Output Power')
# # 绘制斜线阴影
# for i in range(len(table_apt) - 1):
# ax1.fill_between(
# [table_apt['time'].iloc[i], table_apt['time'].iloc[i + 1]],
# [table_apt['power_out'].iloc[i], table_apt['power_out'].iloc[i + 1]],
# color='red', alpha=0.5)
lines, labels = ax1.get_legend_handles_labels()
shadows, shadow_labels = ax2.get_legend_handles_labels()
ax1.legend(lines + shadows, labels + shadow_labels, loc='upper left')
ax1.set_title('Device Data Visualization')
ax1.set_xlabel('Time')
ax1.set_ylabel('Voltage (V)')
ax2.set_ylabel('Power (W)')
plt.ioff()
plt.show()
plt.savefig('output.png')
# plt.close()
plt.ion()
def sim_data_apt(times:tuple[int, int]):
""" 模拟数据 """
@@ -124,13 +202,17 @@ def sim_data_apt(times:tuple[int, int]):
return pd.DataFrame(data)
if __name__=='__main__':
import numpy as np
data = sim_data_apt(('2024-10-1 00:00:00', '2024-10-1 12:00:00'))
# API_HEADER['authorization'] = 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiIl0sInVzZXJfbmFtZSI6IndlYl9tYW5hZ2V8d2FuZ2xlaTQiLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNzMyNTQzMzIyLCJ1c2VySWQiOjI0Mjg1LCJqdGkiOiI2MGZlZjYxNC0zM2QyLTQ5NjMtYjM5Mi1mNTJlYzJhM2RmYTEiLCJjbGllbnRfaWQiOiJ3ZWJfbWFuYWdlIn0.jumI9T8swSPCKITrCU06DWRea0tpvwCidw6jFP-F26JH0fRCp801fbzPs5kHkrgh-sm_ayzO2mD9NCkC2hoC-YDQs8HCvXHZXwtYpn3qJ6vpWRQrMr8Vwk8HnuxbFUn-8Ccs88hHOa8rtrEVsglfl0gqU1C8LL1rsHxgYI3MAwwU_eHo74jNjSHuIn79iq4Gyxc6lial6Pb6WWOw1erqKRGRQPcfUtAXMjwXbQ03vFk6G-As_u353yKvznsGR4A70hFHkJJGugK3en8kJO3_g3sE6ddcx0CYicucRLckro4Md_S8mIPkw2RgGEK38vvEo2fqiyT8E67dC5D4_zMw5A'
data_lamina = Lamina_Data('sqlite:///result/chinatowercom.db')
chart_apt(data)
# data = sim_data_apt(('2024-10-1 00:00:00', '2024-10-1 12:00:00'))
# chart_apt(data)
plt.waitforbuttonpress()
table_apt = data_lamina.graphs_adapter('TTE0102DX2406180988', '2024-11-23 00:00:00', '2024-11-26 00:00:00')
pass
data_lamina.chart_adapter(table_apt)
while True:
plt.waitforbuttonpress()