219 lines
10 KiB
Python
219 lines
10 KiB
Python
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"
|
|
|
|
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 = {
|
|
'apt_temp': ('0305117001', 'adapter', "设备温度"),
|
|
'apt_volt_in': ('0305118001', 'adapter', "输入电压"),
|
|
'apt_curr_in': ('0305119001', 'adapter', "输入电流"),
|
|
'apt_volt_out': ('0305120001', 'adapter', "输出电压"),
|
|
'apt_curr_out': ('0305121001', 'adapter', "输出电流"),
|
|
'apt_power_out': ('0305122001', 'adapter', "输出功率"),
|
|
}
|
|
|
|
class Lamina_Data(object):
|
|
""" 叠光主站数据分析 """
|
|
def __init__(self, database="sqlite:///:memory", header=None):
|
|
""" 初始化 """
|
|
self.engine = create_engine(database)
|
|
|
|
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)
|
|
|
|
self.data = {
|
|
'history': pd.read_sql_table('history', self.engine),
|
|
}
|
|
|
|
self.api_origin = {
|
|
'domain': 'https://energy-iot.chinatowercom.cn/api',
|
|
'header': API_HEADER,
|
|
}
|
|
|
|
def save_history_data(self):
|
|
""" 保存历史数据 """
|
|
|
|
data_memory = self.data['history']
|
|
data_file = pd.read_sql_table('history', self.engine)
|
|
|
|
# 合并新数据和现有数据
|
|
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)
|
|
|
|
print(f"成功插入 {len(combined_df)} 条数据")
|
|
|
|
return len(combined_df)
|
|
|
|
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]):
|
|
""" 模拟数据 """
|
|
t_start = time.mktime(time.strptime(times[0], r"%Y-%m-%d %H:%M:%S"))
|
|
t_end = time.mktime(time.strptime(times[1], r"%Y-%m-%d %H:%M:%S"))
|
|
count_data = (t_end - t_start) / (10 * 60)
|
|
time_list = range(int(t_start), int(t_end), 20 * 60)
|
|
time_list = tuple(map(lambda x: time.strftime(r"%Y-%m-%d %H:%M:%S", time.localtime(x)), time_list))
|
|
data = {
|
|
'time': time_list,
|
|
'volt_in': 10 + 10 * np.random.random(len(time_list)),
|
|
'curr_in': 1 + 2 * np.random.random(len(time_list)),
|
|
'volt_out': 54 + 2 * np.random.random(len(time_list)),
|
|
}
|
|
data['power_out'] = tuple(map(lambda x: x[0] * x[1], zip(data['volt_in'],data['curr_in'])))
|
|
|
|
return pd.DataFrame(data)
|
|
|
|
|
|
if __name__=='__main__':
|
|
|
|
# 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')
|
|
|
|
# data = sim_data_apt(('2024-10-1 00:00:00', '2024-10-1 12:00:00'))
|
|
# chart_apt(data)
|
|
|
|
table_apt = data_lamina.graphs_adapter('TTE0102DX2406180988', '2024-11-23 00:00:00', '2024-11-26 00:00:00')
|
|
|
|
data_lamina.chart_adapter(table_apt)
|
|
while True:
|
|
plt.waitforbuttonpress()
|