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()