积累修改;
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user