Bläddra i källkod

中广核104解析初始化

魏志亮 2 månader sedan
incheckning
28852e7fe4
59 ändrade filer med 4269 tillägg och 0 borttagningar
  1. 2 0
      .gitignore
  2. 1 0
      README.MD
  3. 40 0
      add_or_remove_partition.py
  4. 22 0
      app_run.py
  5. 29 0
      conf/config.yaml
  6. BIN
      conf/主控故障代码表-2406.xlsx
  7. BIN
      conf/主控版本-2406.xlsx
  8. BIN
      conf/故障报警测点-2406.xlsx
  9. 0 0
      conf/故障报警测点.xlsx
  10. BIN
      conf/测点表-2404.xlsx
  11. BIN
      conf/测点表-2405.xlsx
  12. 136 0
      create_table.py
  13. 359 0
      data/ClassIdentifier.py
  14. 101 0
      data/ReadAndSaveDb.py
  15. 12 0
      data/WindFarmDayCount.py
  16. 0 0
      data/__init__.py
  17. 139 0
      parse_scada_data.py
  18. 289 0
      parse_warn_fault_data.py
  19. 8 0
      requirements.txt
  20. 0 0
      service/__init__.py
  21. 5 0
      service/common_connect.py
  22. 45 0
      service/plt_service.py
  23. 254 0
      service/trans_service.py
  24. 0 0
      tmp/__init__.py
  25. 15 0
      tmp/add_yuxian_fault.py
  26. 33 0
      tmp/cedian-extract_分钟.py
  27. 114 0
      tmp/cedian.py
  28. 39 0
      tmp/delete_repeat_data.py
  29. 46 0
      tmp/diff_2_104_file.py
  30. 49 0
      tmp/extract_dbdata_to_csv.py
  31. 81 0
      tmp/generate_minute_sql.py
  32. 59 0
      tmp/generate_minute_sql_sigle_sql.py
  33. 105 0
      tmp/measurepoint.py
  34. 380 0
      tmp/measurepoint2404.py
  35. 351 0
      tmp/measurepoint2405.py
  36. 27 0
      tmp/min_max_nunm.py
  37. 21 0
      tmp/qingli_04月数据.py
  38. 96 0
      tmp/receiver104.py
  39. 68 0
      tmp/tmp_read_file_and_save_db.py
  40. 104 0
      tmp/use_data_generate_csv.py
  41. 115 0
      tmp/use_data_generate_csv11.py
  42. 104 0
      tmp/use_data_generate_csv12.py
  43. 20 0
      tmp/warn_fault_yaml.py
  44. 104 0
      tmp/zhuanhua.py
  45. 12 0
      tmp/再次导入数据.py
  46. 357 0
      tmp/文档生成器.py
  47. 58 0
      tmp/测点转化为yaml.py
  48. 63 0
      tmp/生成测试数据.py
  49. 88 0
      tmp/转发顺序号处理.py
  50. 47 0
      tmp/风场映射.py
  51. 3 0
      utils/__init__.py
  52. 3 0
      utils/conf/__init__.py
  53. 22 0
      utils/conf/read_conf.py
  54. 109 0
      utils/db/ConnectMysql.py
  55. 3 0
      utils/db/__init__.py
  56. 3 0
      utils/log/__init__.py
  57. 38 0
      utils/log/trans_log.py
  58. 0 0
      utils/systeminfo/__init__.py
  59. 90 0
      utils/systeminfo/sysinfo.py

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+/.idea/
+*.iml

+ 1 - 0
README.MD

@@ -0,0 +1 @@
+### 初始化执行  init_table.py 文件

+ 40 - 0
add_or_remove_partition.py

@@ -0,0 +1,40 @@
+import datetime
+
+from dateutil.relativedelta import relativedelta
+
+from service import trans_service
+from utils.log.trans_log import logger
+
+if __name__ == '__main__':
+
+    datas = trans_service.get_all_partitioned_tables()
+
+    now_month = datetime.datetime.now()
+    next_month = now_month + relativedelta(months=1)
+    pname = f'p{str(now_month.year) + str(now_month.month).zfill(2)}'
+    date_str = f'{str(next_month.year)}-{str(next_month.month).zfill(2)}-01'
+    for data in datas:
+        trans_service.add_partition(data['TABLE_NAME'], pname, date_str)
+
+    logger.info("添加分区成功")
+
+    save_month_dict = trans_service.get_sys_conf('online_data_save_month')
+
+    table_types = set()
+
+    for data in datas:
+        table_name = data['TABLE_NAME']
+        wind_factory = table_name.split('_')[0]
+        table_type = table_name.split('_')[1]
+        table_types.add(table_type)
+        del_month = save_month_dict.get(table_type, 12)
+        pmonth = datetime.datetime.now() - relativedelta(months=del_month + 1)
+        trans_service.delelet_partition(table_name, pmonth)
+
+    for table_type in table_types:
+        del_month = save_month_dict.get(table_type, 12)
+        pmonth = datetime.datetime.now() - relativedelta(months=del_month)
+        exists_date = f'{pmonth.year}-{pmonth.month}-01'
+        trans_service.update_expired_data(table_type,exists_date)
+
+    logger.info("删除过期分区成功")

+ 22 - 0
app_run.py

@@ -0,0 +1,22 @@
+import traceback
+import warnings
+from os import path
+
+from utils.conf.read_conf import yaml_conf
+from utils.log.trans_log import logger
+
+warnings.filterwarnings('ignore')
+
+if __name__ == '__main__':
+
+    conf_path = path.abspath(f"./conf/config.yaml")
+    yaml_config = yaml_conf(conf_path)
+
+    from data.ReadAndSaveDb import ReadAndSaveDb
+
+    read_and_save = ReadAndSaveDb()
+    try:
+        read_and_save.run()
+    except:
+        logger.info("执行出错")
+        logger.info(traceback.format_exc())

+ 29 - 0
conf/config.yaml

@@ -0,0 +1,29 @@
+#plt:
+#  host: 192.168.50.233
+#  port: 3306
+#  user: admin
+#  password: admin123456
+#  database: energy_prod
+
+plt:
+  host: 192.168.50.235
+  port: 4000
+  user: root
+  password: '123456'
+  database: energy
+
+
+trans:
+  host: 192.168.50.241
+  port: 4000
+  user: root
+  password: '123456'
+  database: energy_data
+
+
+# 日志保存路径
+log_path_dir: /home/trans/project/logs/104_parse
+
+#data_base_dir: /home/trans/data
+
+data_base_dir: C:\Users\wzl\Desktop\中广核104测点\0415新数据

BIN
conf/主控故障代码表-2406.xlsx


BIN
conf/主控版本-2406.xlsx


BIN
conf/故障报警测点-2406.xlsx


+ 0 - 0
conf/故障报警测点.xlsx


BIN
conf/测点表-2404.xlsx


BIN
conf/测点表-2405.xlsx


+ 136 - 0
create_table.py

@@ -0,0 +1,136 @@
+import datetime
+
+from dateutil.relativedelta import relativedelta
+
+from service import plt_service
+from service.common_connect import trans
+
+base_scada_create_sql = """
+        CREATE TABLE
+        IF NOT EXISTS `{table_name}` (
+            `wind_turbine_number` VARCHAR (20) DEFAULT NULL COMMENT '风机编号',
+            `wind_turbine_name` VARCHAR(20) DEFAULT NULL COMMENT '风机原始名称',
+            `time_stamp` datetime NOT NULL COMMENT '时间戳',
+            `active_power` DOUBLE DEFAULT NULL COMMENT '有功功率',
+            `rotor_speed` DOUBLE DEFAULT NULL COMMENT '风轮转速',
+            `generator_speed` DOUBLE DEFAULT NULL COMMENT '发电机转速',
+            `wind_velocity` DOUBLE DEFAULT NULL COMMENT '风速',
+            `pitch_angle_blade_1` DOUBLE DEFAULT NULL COMMENT '桨距角1',
+            `pitch_angle_blade_2` DOUBLE DEFAULT NULL COMMENT '桨距角2',
+            `pitch_angle_blade_3` DOUBLE DEFAULT NULL COMMENT '桨距角3',
+            `cabin_position` DOUBLE DEFAULT NULL COMMENT '机舱位置',
+            `true_wind_direction` DOUBLE DEFAULT NULL COMMENT '绝对风向',
+            `yaw_error1` DOUBLE DEFAULT NULL COMMENT '对风角度',
+            `set_value_of_active_power` DOUBLE DEFAULT NULL COMMENT '有功功率设定值',
+            `gearbox_oil_temperature` DOUBLE DEFAULT NULL COMMENT '齿轮箱油温',
+            `generatordrive_end_bearing_temperature` DOUBLE DEFAULT NULL COMMENT '发电机驱动端轴承温度',
+            `generatornon_drive_end_bearing_temperature` DOUBLE DEFAULT NULL COMMENT '发电机非驱动端轴承温度',
+            `cabin_temperature` DOUBLE DEFAULT NULL COMMENT '机舱内温度',
+            `twisted_cable_angle` DOUBLE DEFAULT NULL COMMENT '扭缆角度',
+            `front_back_vibration_of_the_cabin` DOUBLE DEFAULT NULL COMMENT '机舱前后振动',
+            `side_to_side_vibration_of_the_cabin` DOUBLE DEFAULT NULL COMMENT '机舱左右振动',
+            `actual_torque` DOUBLE DEFAULT NULL COMMENT '实际力矩',
+            `given_torque` DOUBLE DEFAULT NULL COMMENT '给定力矩',
+            `clockwise_yaw_count` DOUBLE DEFAULT NULL COMMENT '顺时针偏航次数',
+            `counterclockwise_yaw_count` DOUBLE DEFAULT NULL COMMENT '逆时针偏航次数',
+            `unusable` DOUBLE DEFAULT NULL COMMENT '不可利用',
+            `power_curve_available` DOUBLE DEFAULT NULL COMMENT '功率曲线可用',
+            `required_gearbox_speed` DOUBLE DEFAULT NULL COMMENT '齿轮箱转速',
+            `inverter_speed_master_control` DOUBLE DEFAULT NULL COMMENT '变频器转速(主控)',
+            `outside_cabin_temperature` DOUBLE DEFAULT NULL COMMENT '环境温度',
+            `main_bearing_temperature` DOUBLE DEFAULT NULL COMMENT '主轴承轴承温度',
+            `gearbox_high_speed_shaft_bearing_temperature` DOUBLE DEFAULT NULL COMMENT '齿轮箱高速轴轴承温度',
+            `gearboxmedium_speed_shaftbearing_temperature` DOUBLE DEFAULT NULL COMMENT '齿轮箱中速轴轴承温度',
+            `gearbox_low_speed_shaft_bearing_temperature` DOUBLE DEFAULT NULL COMMENT '齿轮箱低速轴轴承温度',
+            `generator_winding1_temperature` DOUBLE DEFAULT NULL COMMENT '发电机绕组1温度',
+            `generator_winding2_temperature` DOUBLE DEFAULT NULL COMMENT '发电机绕组2温度',
+            `generator_winding3_temperature` DOUBLE DEFAULT NULL COMMENT '发电机绕组3温度',
+            `wind_turbine_status` DOUBLE DEFAULT NULL COMMENT '风机状态1',
+            `wind_turbine_status2` DOUBLE DEFAULT NULL COMMENT '风机状态2',
+            `turbulence_intensity` DOUBLE DEFAULT NULL COMMENT '湍流强度',
+            `lab` int DEFAULT NULL COMMENT '-1:停机 0:好点  1:欠发功率点;2:超发功率点;3:额定风速以上的超发功率点 4: 限电',
+            `year` INT (4) DEFAULT NULL COMMENT '年',
+            `month` INT (2) DEFAULT NULL COMMENT '月',
+            `day` INT (2) DEFAULT NULL COMMENT '日',
+            `year_month` int(6) DEFAULT NULL COMMENT '年-月',
+             KEY `time_stamp` (`time_stamp`),
+             KEY `wind_turbine_number` (`wind_turbine_number`)
+            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='{wind_name}{trans_type}数据表'
+        """
+
+base_warn_fault_sql = """
+    CREATE TABLE
+    IF NOT EXISTS `{table_name}` (
+  `wind_turbine_number` varchar(20) DEFAULT NULL COMMENT '风机编号',
+  `wind_turbine_name` varchar(20) DEFAULT NULL COMMENT '原始风机编号',
+  `mc_version` varchar(50)  DEFAULT NULL COMMENT '主控版本号',
+  `seq_no` int default NULL comment '实时数据顺序号',
+  `begin_time` datetime DEFAULT NULL COMMENT '开始时间',
+  `end_time` datetime DEFAULT NULL COMMENT '结束时间',
+  `time_diff` int DEFAULT NULL COMMENT '处理耗时,单位秒',
+  `fault_id` varchar(20) DEFAULT NULL COMMENT '报警或者故障ID',
+  `fault_code` varchar(50) DEFAULT NULL COMMENT '报警或者故障CODE',
+  `fault_detail` varchar(255) DEFAULT NULL COMMENT '错误描述',
+  `fault_level` varchar(20) DEFAULT NULL COMMENT '报警等级',
+  `fault_type` varchar(20) DEFAULT NULL COMMENT '报警类型',
+  `stop_status` varchar(20) DEFAULT NULL COMMENT '刹车状态',
+  KEY `wind_turbine_number` (`wind_turbine_number`),
+  KEY  `seq_no` (`seq_no`),
+  KEY `begin_time` (`begin_time`),
+  KEY `end_time` (`end_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='{wind_name}{trans_type}数据表'
+
+"""
+
+
+def creat_scada_table(wind_code, wind_name):
+    types = ['minute', 'second']
+    for trans_type in types:
+        table_name = f'{wind_code}_{trans_type}'
+
+        create_sql = base_scada_create_sql.format_map(
+            {'table_name': table_name, 'wind_name': wind_name, 'trans_type': trans_type})
+
+        create_sql = create_sql + ' PARTITION BY RANGE COLUMNS(time_stamp) ( \n'
+
+        now_month = datetime.datetime.today()
+
+        for i in range(1, 3):
+            next_month = now_month + relativedelta(months=1)
+            create_sql = create_sql + (f" PARTITION p{str(now_month.year) + str(now_month.month).zfill(2)} "
+                                       f"VALUES LESS THAN ('{str(next_month.year)}-{str(next_month.month).zfill(2)}-01'),\n")
+            now_month = next_month
+
+        create_sql = create_sql + " PARTITION pmax VALUES LESS THAN (MAXVALUE)\n );"
+
+        trans.execute(create_sql)
+
+
+def create_warn_fault_table(wind_code, wind_name):
+    types = ['warn', 'fault']
+    for trans_type in types:
+        table_name = f'{wind_code}_{trans_type}'
+        create_sql = base_warn_fault_sql.format_map(
+            {'table_name': table_name, 'wind_name': wind_name, 'trans_type': trans_type})
+
+        create_sql = create_sql + ' PARTITION BY RANGE COLUMNS(begin_time) ( \n'
+
+        now_month = datetime.datetime.today()
+
+        for i in range(1, 3):
+            next_month = now_month + relativedelta(months=1)
+            create_sql = create_sql + (f" PARTITION p{str(now_month.year) + str(now_month.month).zfill(2)} "
+                                       f"VALUES LESS THAN ('{str(next_month.year)}-{str(next_month.month).zfill(2)}-01'),\n")
+            now_month = next_month
+
+        create_sql = create_sql + " PARTITION pmax VALUES LESS THAN (MAXVALUE)\n );"
+
+        trans.execute(create_sql)
+
+
+if __name__ == '__main__':
+    datas = plt_service.get_all_wind()
+
+    for data in datas:
+        create_warn_fault_table(data['code_number'], data['code_name'])
+        creat_scada_table(data['code_number'], data['code_name'])

+ 359 - 0
data/ClassIdentifier.py

@@ -0,0 +1,359 @@
+import datetime
+import traceback
+
+import numpy as np
+from pandas import DataFrame
+
+from utils.log.trans_log import logger
+
+
+class ClassIdentifier(object):
+    """
+    分类标识 -1:停机 0:好点  1:欠发功率点;2:超发功率点;3:额定风速以上的超发功率点 4: 限电
+    """
+
+    def __init__(self, wind_turbine_number="", origin_df: DataFrame = None,
+                 wind_velocity='wind_velocity',
+                 active_power='active_power',
+                 pitch_angle_blade='pitch_angle_blade_1',
+                 rated_power=1500, cut_out_speed=20):
+        """
+        :param origin_df: The pandas DataFrame containing the input data.
+        :param wind_velocity: 风速字段
+        :param active_power: 有功功率字段
+        :param pitch_angle_blade: 桨距角
+        :param rated_power: 额定功率
+        :param cut_out_speed: 切出风速
+        """
+        self.wind_turbine_number = wind_turbine_number
+        self.wind_velocity = wind_velocity
+        self.active_power = active_power
+        self.pitch_angle_blade = pitch_angle_blade
+        self.rated_power = rated_power  # 额定功率1500kw,可改为2000kw
+        self.cut_out_speed = cut_out_speed
+
+        if self.rated_power is None:
+            logger.info(f"{wind_turbine_number} WARNING:rated_power配置为空的")
+            self.rated_power = 1500
+
+        if self.cut_out_speed is None:
+            logger.info(f"{cut_out_speed} WARNING:cut_out_speed配置为空的")
+            self.cut_out_speed = 20
+
+        self.df = origin_df
+
+    def identifier(self):
+        # 风速 和 有功功率 df
+        # self.df = self.df[[self.wind_velocity, self.active_power, "pitch_angle_blade_1"]]
+        self.df.reset_index(inplace=True)
+
+        if len(self.df[self.active_power].unique()) <= 10:
+            self.df['lab'] = -1
+            return self.df
+
+        wind_and_power_df_count = self.df.shape[0]
+        power_max = self.df[self.active_power].max()
+        power_rated = np.ceil(power_max / 100) * 100
+        v_cut_out = self.cut_out_speed
+        # 网格法确定风速风向分区数量,功率方向分区数量,
+        power_bin_count = int(np.ceil(power_rated / 25))  # 功率分区间隔25kW
+        velocity_bin_count = int(np.ceil(v_cut_out / 0.25))  # 风速分区间隔0.25m/s
+
+        # 存储功率大于零的运行数据
+        power_gt_zero_array = np.zeros([wind_and_power_df_count, 2], dtype=float)
+        power_gt_zero_array_count = 0
+        for i in range(wind_and_power_df_count):
+            if self.df.loc[i, self.active_power] > 0:
+                power_gt_zero_array[power_gt_zero_array_count, 0] = self.df.loc[i, self.wind_velocity]
+                power_gt_zero_array[power_gt_zero_array_count, 1] = self.df.loc[i, self.active_power]
+
+                power_gt_zero_array_count = power_gt_zero_array_count + 1
+
+        # 统计各网格落入的散点个数
+        x_box_number = np.zeros([power_bin_count, velocity_bin_count], dtype=int)
+
+        n_which_p = -1
+        n_which_v = -1
+        for i in range(power_gt_zero_array_count):
+            for m in range(power_bin_count):
+                if m * 25 < power_gt_zero_array[i, 1] <= (m + 1) * 25:
+                    n_which_p = m
+                    break
+
+            for n in range(velocity_bin_count):
+                if (n * 0.25 + 0.125) < power_gt_zero_array[i, 0] <= ((n + 1) * 0.25 + 0.125):
+                    n_which_v = n
+                    break
+
+            if n_which_p > -1 and n_which_v > -1:
+                x_box_number[n_which_p, n_which_v] = x_box_number[n_which_p, n_which_v] + 1
+
+        # 在功率方向将网格内散点绝对个数转换为相对百分比,备用
+        power_box_percent = np.zeros([power_bin_count, velocity_bin_count], dtype=float)
+
+        # 功率方向统计
+        power_bin_sum = np.zeros(power_bin_count, dtype=int)
+
+        for i in range(power_bin_count):
+            power_bin_sum[i] = sum(x_box_number[i, :])
+            # for m in range(velocity_bin_count):
+            #     power_bin_sum[i] = power_bin_sum[i] + x_box_number[i, m]
+
+            for m in range(velocity_bin_count):
+                if power_bin_sum[i] > 0:
+                    power_box_percent[i, m] = x_box_number[i, m] / power_bin_sum[i] * 100
+
+        # 在风速方向将网格内散点绝对个数转换为相对百分比,备用
+        v_box_percent = np.zeros([power_bin_count, velocity_bin_count], dtype=float)
+        v_bin_sum = np.zeros(velocity_bin_count, dtype=int)
+
+        for i in range(velocity_bin_count):
+            v_bin_sum[i] = sum(x_box_number[:, i])
+            # for m in range(power_bin_count):
+            #     v_bin_sum[i] = v_bin_sum[i] + x_box_number[m, i]
+
+            for m in range(power_bin_count):
+                if v_bin_sum[i] > 0:
+                    v_box_percent[m, i] = x_box_number[m, i] / v_bin_sum[i] * 100
+
+        # 以水平功率带方向为准,分析每个水平功率带中,功率主带中心,即找百分比最大的网格位置。
+        p_box_max_index = np.zeros(power_bin_count, dtype=int)  # 水平功率带最大网格位置索引
+        p_box_max_p = np.zeros(power_bin_count, dtype=int)  # 水平功率带最大网格百分比
+
+        for m in range(power_bin_count):
+            # 确定每一水平功率带的最大网格位置索引即百分比值
+            p_box_max_p[m], p_box_max_index[m] = power_box_percent[m, :].max(), power_box_percent[m, :].argmax()
+
+        # 切入风速特殊处理,如果切入风速过于偏右,向左拉回
+        # todo 为什么第一行数据的索引值 > 14个就要往左拉回,还有是不是不叫切入风速,这个是 落入这个区间功率最多的个数的索引值
+        if p_box_max_index[0] > 14:
+            p_box_max_index[0] = 9
+
+        # 以水平功率带方向为基准,进行分析
+        dot_dense_left_right = np.zeros([power_bin_count, 2], dtype=int)  # 存储每一水平功率带的功率主带以最大网格为中心,向向左,向右扩展的网格数
+        dot_valve = 90  # 从中心向左右对称扩展网格的散点百分比和的阈值。
+
+        for i in range(power_bin_count - 6):  # 从最下层水平功率带1开始,向上到第PNum-6个水平功率带(额定功率一下水平功率带),逐一分析
+            p_dot_dense_sum = p_box_max_p[i]  # 以中心最大水平功率带为基准,向左向右对称扩展网格,累加各网格散点百分比
+            i_spread_right = 1
+            i_spread_left = 1
+            while p_dot_dense_sum < dot_valve:
+
+                if (p_box_max_index[i] + i_spread_right) < velocity_bin_count - 1:
+                    # 向右侧扩展
+                    p_dot_dense_sum = p_dot_dense_sum + power_box_percent[i, p_box_max_index[i] + i_spread_right]
+                    i_spread_right = i_spread_right + 1
+
+                if (p_box_max_index[i] + i_spread_right) > velocity_bin_count - 1:
+                    break
+
+                if (p_box_max_index[i] - i_spread_left) > 0:
+                    # 向左侧扩展
+                    p_dot_dense_sum = p_dot_dense_sum + power_box_percent[i, p_box_max_index[i] - i_spread_left]
+                    i_spread_left = i_spread_left + 1
+
+                if (p_box_max_index[i] - i_spread_left) <= 0:
+                    break
+
+            i_spread_right = i_spread_right - 1
+            i_spread_left = i_spread_left - 1
+            # 向左右对称扩展完毕
+
+            dot_dense_left_right[i, 0] = i_spread_left
+            dot_dense_left_right[i, 1] = i_spread_right
+
+        main_band_right = np.median(dot_dense_left_right[:, 1])
+
+        # 散点向右显著延展分布的水平功率带为限功率水平带
+        # 各水平功率带是否为限功率标识,==1:是;==0:不是
+        power_limit = np.zeros([power_bin_count, 1], dtype=int)
+        width_average = 0  # 功率主带平均宽度
+
+        # todo 限功率主带判别阈值为什么要加3
+        power_limit_valve = np.ceil(main_band_right) + 3  # 限功率主带判别阈值
+        n_counter = 0
+
+        for i in range(power_bin_count - 6):
+            # 如果向右扩展网格数大于阈值,且该水平功率带点总数>20,是限功率
+            if dot_dense_left_right[i, 1] > power_limit_valve and power_bin_sum[i] > 20:
+                power_limit[i] = 1
+
+            if dot_dense_left_right[i, 1] <= power_limit_valve:
+                # 统计正常水平功率带右侧宽度
+                width_average = width_average + dot_dense_left_right[i, 1]
+                n_counter = n_counter + 1
+
+        width_average = width_average / n_counter  # 功率主带平均宽度
+
+        # 对限负荷水平功率带的最大网格较下面相邻层显著偏右,拉回
+        for i in range(1, power_bin_count - 6):
+            if power_limit[i] == 1 and abs(p_box_max_index[i] - p_box_max_index[i - 1]) > 5:
+                p_box_max_index[i] = p_box_max_index[i - 1] + 1
+
+        # 功率主带的右边界
+        curve_width = int(np.ceil(width_average) + 2)
+
+        # 数据异常需要剔除的网格标识,标识1:功率主带右侧的欠发网格;2:功率主带左侧的超发网格 3:额定功率以上的超发点
+        b_box_remove = np.zeros([power_bin_count, velocity_bin_count], dtype=int)
+
+        for m in range(power_bin_count - 6):
+            for n in range(p_box_max_index[m] + curve_width, velocity_bin_count):
+                b_box_remove[m, n] = 1
+
+            for n in range(p_box_max_index[m] - curve_width, -1, -1):
+                b_box_remove[m, n] = 2
+
+        # 确定功率主带的左上拐点,即额定风速位置的网格索引
+        curve_top = np.zeros(2, dtype=int)
+        curve_top_valve = 3  # 网格的百分比阈值
+        b_top_find = False
+        for m in range(power_bin_count - 5, -1, -1):
+            for n in range(velocity_bin_count):
+                # 如左上角网格的百分比和散点个数大于阈值。
+                if v_box_percent[m, n] > curve_top_valve and x_box_number[m, n] >= 10:
+                    curve_top[0] = m
+                    curve_top[1] = n
+                    b_top_find = True
+                    break
+
+            if b_top_find:
+                break
+
+        isolate_valve = 3
+        for m in range(power_bin_count - 6):
+            for n in range(p_box_max_index[m] + curve_width, velocity_bin_count):
+                if power_box_percent[m, n] < isolate_valve:
+                    b_box_remove[m, n] = 1
+
+        # 功率主带顶部宽度
+        curve_width_t = 2
+        for m in range(power_bin_count - curve_width_t - 1, power_bin_count):
+            for n in range(velocity_bin_count):
+                b_box_remove[m, n] = 3  # 网格为额定功率以上的超发点
+
+        # 功率主带拐点左侧的欠发网格标识
+        for m in range(power_bin_count - 5 - 1, power_bin_count):
+            for n in range(curve_top[1] - 1):
+                b_box_remove[m, n] = 2
+
+        # 以网格的标识,决定该网格内数据的标识。dzwind_and_power_sel。散点在哪个网格,此网格的标识即为该点的标识
+        # -1:停机 0:好点  1:欠发功率点;2:超发功率点;3:额定风速以上的超发功率点 4: 限电
+        dzwind_and_power_sel = np.zeros(power_gt_zero_array_count, dtype=int)
+        n_which_p = -1
+        n_which_v = -1
+
+        for i in range(power_gt_zero_array_count):
+            for m in range(power_bin_count):
+                if m * 25 < power_gt_zero_array[i, 1] <= (m + 1) * 25:
+                    n_which_p = m
+                    break
+
+            for n in range(velocity_bin_count):
+                if (n * 0.25 + 0.125) < power_gt_zero_array[i, 0] <= ((n + 1) * 0.25 + 0.125):
+                    n_which_v = n
+                    break
+
+            if n_which_p > -1 and n_which_v > -1:
+                if b_box_remove[n_which_p, n_which_v] == 1:
+                    dzwind_and_power_sel[i] = 1
+
+                if b_box_remove[n_which_p, n_which_v] == 2:
+                    dzwind_and_power_sel[i] = 2
+
+                if b_box_remove[n_which_p, n_which_v] == 3:
+                    dzwind_and_power_sel[i] = 0  # 3  # 额定风速以上的超发功率点认为是正常点,不再标识。
+
+        # 限负荷数据标识方法2:把数据切割为若干个窗口。对每一窗口,以第一个点为基准,连续nWindowLength个数据的功率在方差范围内,呈现显著水平分布的点
+        n_window_length = 3
+        limit_window = np.zeros(n_window_length, dtype=float)
+        power_std = 15  # 功率波动方差
+        n_window_num = int(np.floor(power_gt_zero_array_count / n_window_length))
+        power_limit_up = self.rated_power - 300
+        power_limit_low = 200
+        for i in range(n_window_num):
+            for j in range(n_window_length):
+                limit_window[j] = power_gt_zero_array[i * n_window_length + j, 1]
+
+            b_all_in_areas = 1
+            for j in range(n_window_length):
+                if limit_window[j] < power_limit_low or limit_window[j] > power_limit_up:
+                    b_all_in_areas = 0
+
+            if b_all_in_areas == 0:
+                continue
+
+            up_limit = limit_window[0] + power_std
+            low_limit = limit_window[0] - power_std
+            b_all_in_up_low = 1
+            for j in range(1, n_window_length):
+                if limit_window[j] < low_limit or limit_window[j] > up_limit:
+                    b_all_in_up_low = 0
+
+            if b_all_in_up_low == 1:
+                for j in range(n_window_length):
+                    dzwind_and_power_sel[i * n_window_length + j] = 4  # 标识窗口内的数据为限负荷数据
+
+        for i in range(power_bin_count - 6):
+            pv_left_down = np.zeros(2, dtype=float)
+            pv_right_up = np.zeros(2, dtype=float)
+
+            if (p_box_max_index[i + 1] - p_box_max_index[i]) >= 1:
+                pv_left_down[0] = (p_box_max_index[i] + curve_width) * 0.25 + 0.125
+                pv_left_down[1] = i * 25
+
+                pv_right_up[0] = (p_box_max_index[i + 1] + curve_width) * 0.25 + 0.125
+                pv_right_up[1] = (i + 1) * 25
+
+                for m in range(power_gt_zero_array_count):
+                    if pv_left_down[0] < power_gt_zero_array[m, 0] < pv_right_up[0] and \
+                            pv_left_down[1] < power_gt_zero_array[m, 1] < pv_right_up[1]:  # 在该锯齿中
+                        if (power_gt_zero_array[m, 1] - pv_left_down[1]) / (
+                                power_gt_zero_array[m, 0] - pv_left_down[0]) > (
+                                pv_right_up[1] - pv_left_down[1]) / (
+                                pv_right_up[0] - pv_left_down[0]):  # 斜率大于对角连线,则在锯齿左上三角形中,选中
+                            dzwind_and_power_sel[m] = 0
+
+        self.df.loc[:, 'lab'] = -1
+        self.df.loc[
+            self.df[self.df[self.active_power] > 0].index, 'lab'] = dzwind_and_power_sel
+
+        # 把部分欠发的优化为限电
+        # 构建条件表达式
+        cond1 = (self.df['lab'] == 1) & (
+                (self.df[self.active_power] < self.rated_power * 0.75) &
+                (self.df[self.pitch_angle_blade] > 0.5)
+        )
+        cond2 = (self.df['lab'] == 1) & (
+                (self.df[self.active_power] < self.rated_power * 0.85) &
+                (self.df[self.pitch_angle_blade] > 1.5)
+        )
+        cond3 = (self.df['lab'] == 1) & (
+                (self.df[self.active_power] < self.rated_power * 0.9) &
+                (self.df[self.pitch_angle_blade] > 2.5)
+        )
+
+        # 使用逻辑或操作符|合并条件
+        combined_condition = cond1 | cond2 | cond3
+        self.df.loc[combined_condition, 'lab'] = 4
+
+        self.df.loc[self.df[self.active_power] <= 0, 'lab'] = -1
+
+        self.df.reset_index(drop=True, inplace=True)
+        if 'index' in self.df.columns:
+            del self.df['index']
+        return self.df
+
+    def run(self):
+        # Implement your class identification logic here
+        begin = datetime.datetime.now()
+        logger.info(f"打标签开始,风机号:{self.wind_turbine_number},数量:{self.df.shape}")
+        try:
+            df = self.identifier()
+        except Exception as e:
+            logger.error(traceback.format_exc())
+            # message = str(e) + ',风机编号:' + self.wind_turbine_number
+            # raise Exception('打标签失败:' + message)
+            self.df.loc[:, 'lab'] = -999
+            return self.df
+        logger.info(f"打标签结束,{df.shape},耗时:{datetime.datetime.now() - begin}")
+        return df

+ 101 - 0
data/ReadAndSaveDb.py

@@ -0,0 +1,101 @@
+import datetime
+import multiprocessing
+import traceback
+from concurrent.futures import ThreadPoolExecutor
+
+import pandas as pd
+
+from data.ClassIdentifier import ClassIdentifier
+from data.WindFarmDayCount import WindFarmDayCount
+from service import trans_service
+from service.plt_service import get_wind_info
+from utils.conf.read_conf import read_conf
+from utils.log.trans_log import logger
+
+
+class ReadAndSaveDb(object):
+
+    def __init__(self):
+        self.yesterday_tables: list[WindFarmDayCount] = self.get_yesterday_tables()
+
+    def get_yesterday_tables(self):
+        yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
+        date_str = yesterday.strftime('%Y-%m-%d')
+        all_datas = trans_service.get_yesterday_tables(date_str)
+        if isinstance(all_datas, tuple()):
+            return []
+
+        tables = list()
+        for data in all_datas:
+            tables.append(WindFarmDayCount(data))
+
+        return tables
+
+    def process_single_turbine(self, df, wind_turbine_number, rated_power_and_cutout_speed_map):
+        df['time_stamp'] = pd.to_datetime(df['time_stamp'], errors="coerce")
+        df.dropna(subset=['time_stamp'], inplace=True)
+        df.sort_values(by='time_stamp', inplace=True)
+        logger.info(f"有功功率前10个 :{df.head(10)['active_power'].values}")
+        power_df = df[df['active_power'] > 0]
+        logger.info(f"{wind_turbine_number} 功率大于0的数量:{power_df.shape}")
+        power = power_df.sample(int(power_df.shape[0] / 100))['active_power'].median()
+        logger.info(f"{wind_turbine_number} 有功功率,中位数:{power}")
+        if power > 100000:
+            df['active_power'] = df['active_power'] / 1000
+
+        rated_power_and_cutout_speed_tuple = read_conf(rated_power_and_cutout_speed_map, str(wind_turbine_number), None)
+        if rated_power_and_cutout_speed_tuple is None:
+            rated_power_and_cutout_speed_tuple = (None, None)
+
+        if power_df.shape[0] == 0:
+            df.loc[:, 'lab'] = -1
+        else:
+            class_identifiler = ClassIdentifier(wind_turbine_number=wind_turbine_number, origin_df=df,
+                                                rated_power=rated_power_and_cutout_speed_tuple[0],
+                                                cut_out_speed=rated_power_and_cutout_speed_tuple[1])
+            df = class_identifiler.run()
+
+        del power_df
+
+        if not df.empty:
+            df['year'] = df['time_stamp'].dt.year
+            df['month'] = df['time_stamp'].dt.month
+            df['day'] = df['time_stamp'].dt.day
+            df['time_stamp'] = df['time_stamp'].apply(lambda x: x.strftime('%Y-%m-%d %H:%M:%S'))
+            df['year_month'] = df[['year', 'month']].apply(lambda x: str(x['year']) + str(x['month']).zfill(2), axis=1)
+            return df
+
+        return df
+
+    def read_and_save_db(self, windFarmDayCount: WindFarmDayCount):
+        logger.info(f"开始执行:{str(windFarmDayCount)}")
+        try:
+            table_name = f"{windFarmDayCount.wind_farm_code}_{windFarmDayCount.type}"
+            table_name_tmp = table_name + f"_{str(windFarmDayCount.add_date).replace('-', '_')}_tmp"
+            wind_col_trans, rated_power_and_cutout_speed_map = get_wind_info(windFarmDayCount.wind_farm_code)
+            df = trans_service.read_data_from_table(table_name_tmp)
+            df['wind_turbine_name'] = df['wind_turbine_name'].astype('str')
+            df['wind_turbine_number'] = df['wind_turbine_name'].map(wind_col_trans).fillna(df['wind_turbine_name'])
+            wind_turbine_numbers = df['wind_turbine_number'].unique()
+
+            dfs = []
+            with ThreadPoolExecutor(max_workers=5, thread_name_prefix=windFarmDayCount.wind_farm_name) as executor:
+                for wind_turbine_number in wind_turbine_numbers:
+                    dfs.append(
+                        executor.submit(self.process_single_turbine,
+                                        df[df['wind_turbine_number'] == wind_turbine_number],
+                                        wind_turbine_number, rated_power_and_cutout_speed_map).result())
+
+            result_df = pd.concat(dfs)
+            trans_service.load_data_local(table_name, result_df)
+            trans_service.drop_table(table_name_tmp)
+            trans_service.update_sync(windFarmDayCount.id)
+            logger.info(f"{str(windFarmDayCount)}保存成功")
+        except:
+            logger.info(f"{str(windFarmDayCount)}出现错误")
+            logger.info(traceback.format_exc())
+            # raise Exception(f"{str(windFarmDayCount)}出现错误")
+
+    def run(self):
+        with multiprocessing.Pool(2) as pool:
+            pool.map(self.read_and_save_db, self.yesterday_tables)

+ 12 - 0
data/WindFarmDayCount.py

@@ -0,0 +1,12 @@
+class WindFarmDayCount(object):
+
+    def __init__(self, data):
+        self.data = data
+        self.id = data['id']
+        self.wind_farm_code = data['wind_farm_code']
+        self.wind_farm_name = data['wind_farm_name']
+        self.add_date = data['add_date']
+        self.type = data['type']
+
+    def __str__(self):
+        return str(self.data)

+ 0 - 0
data/__init__.py


+ 139 - 0
parse_scada_data.py

@@ -0,0 +1,139 @@
+"""
+读取104规约返回的数据,并标准化到临时表中
+"""
+import multiprocessing
+import os.path
+import time
+import traceback
+import warnings
+from datetime import datetime
+
+import pandas as pd
+
+from service import plt_service, trans_service
+from utils.conf.read_conf import yaml_conf, read_conf
+from utils.log.trans_log import logger
+
+warnings.filterwarnings('ignore')
+
+
+def generate_mesurepoint_maps(file_path):
+    df = pd.read_excel(file_path)
+
+    wind_maps = dict()
+    for _, data in df.iterrows():
+        shunxuhao = int(data['顺序号']) + 1
+        changzhan = data['场站标准化编号']
+        wind_no = data['风机号']
+        en_name = data['标准化英文']
+        if changzhan in wind_maps.keys():
+            if wind_no in wind_maps[changzhan].keys():
+                wind_maps[changzhan][wind_no][shunxuhao] = en_name
+            else:
+                wind_maps[changzhan][wind_no] = {shunxuhao: en_name}
+        else:
+            wind_maps[changzhan] = {wind_no: {shunxuhao: en_name}}
+
+    return wind_maps
+
+
+def generate_scada_data(df, mesurepoint_maps, changzhan, wind_code_name_map):
+    second_dfs = list()
+    minute_dfs = list()
+    wind_maps, _ = plt_service.get_wind_info(changzhan, False)
+
+    for wind_no in mesurepoint_maps[changzhan].keys():
+        shunxuhao_map = mesurepoint_maps[changzhan][wind_no]
+        second_df = df[list(shunxuhao_map.keys())]
+        second_df['wind_turbine_name'] = wind_no
+        second_df['time_stamp'] = df[0]
+        second_df['time_stamp'] = pd.to_datetime(second_df['time_stamp'])
+        second_df.rename(columns=shunxuhao_map, inplace=True)
+        second_dfs.append(second_df)
+        minute_df = second_df.copy(deep=True)
+        minute_df['time_stamp'] = minute_df['time_stamp'].min().strftime('%Y-%m-%d %H:%M:00')
+        minute_df = minute_df.groupby(['wind_turbine_name', 'time_stamp']).mean(numeric_only=True).reset_index()
+        minute_dfs.append(minute_df)
+
+    changzhan_second_df = pd.concat(second_dfs, ignore_index=True)
+    changzhan_minute_df = pd.concat(minute_dfs, ignore_index=True)
+
+    changzhan_second_df['wind_turbine_name'] = changzhan_second_df['wind_turbine_name'].astype(str)
+    changzhan_second_df['wind_turbine_number'] = changzhan_second_df['wind_turbine_name'].map(wind_maps)
+
+    changzhan_minute_df['wind_turbine_name'] = changzhan_minute_df['wind_turbine_name'].astype(str)
+    changzhan_minute_df['wind_turbine_number'] = changzhan_minute_df['wind_turbine_name'].map(wind_maps)
+
+    # changzhan_second_df.to_csv(f'tmp/104/scada/{changzhan}-{int(time.time())}_second.csv', index=False)
+    # changzhan_minute_df.to_csv(f'tmp/104/scada/{changzhan}-{int(time.time())}_minute.csv', index=False)
+
+    date_str = datetime.now().strftime('%Y_%m_%d')
+    second_table_name = f'{changzhan}_second_{date_str}_tmp'
+    trans_service.save_df_to_db(second_table_name, changzhan_second_df)
+
+    minute_table_name = f'{changzhan}_minute_{date_str}_tmp'
+    trans_service.save_df_to_db(minute_table_name, changzhan_minute_df)
+    changzhan_minute_df['time_stamp'] = pd.to_datetime(changzhan_minute_df['time_stamp'], errors='coerce')
+    minute_max_date = changzhan_minute_df['time_stamp'].max()
+    second_max_date = changzhan_second_df['time_stamp'].max()
+    add_date_str = minute_max_date.strftime('%Y-%m-%d')
+
+    minunte_last_date_str = minute_max_date
+    second_last_date_str = second_max_date.strftime('%Y-%m-%d %H:%M:%S')
+
+    # wind_farm_code, wind_farm_name, add_date, trans_type, count, latest_data_time
+    trans_service.update_wind_farm_day_count(changzhan, wind_code_name_map.get(changzhan, ''), add_date_str,
+                                             'minute', changzhan_minute_df.shape[0], minunte_last_date_str)
+
+    trans_service.update_wind_farm_day_count(changzhan, wind_code_name_map.get(changzhan, ''), add_date_str,
+                                             'second', changzhan_second_df.shape[0], second_last_date_str)
+
+
+def add_table(changzhan_names):
+    types = ['minute', 'second']
+
+    for changzhan_name in changzhan_names:
+        for type in types:
+            table_name = f'{changzhan_name}_{type}_{date_str}_tmp'
+
+            if not trans_service.boolean_table_exists(table_name):
+                trans_service.create_tmp_table(table_name)
+
+
+if __name__ == '__main__':
+    time.sleep(60)
+    total_begin = time.time()
+    begin = time.time()
+
+    date_str = datetime.now().strftime('%Y_%m_%d')
+
+    wind_code_name_map = plt_service.get_all_wind_by_company_code('COM00002')
+
+    conf_path = os.path.abspath(f"./conf/config.yaml")
+    yaml_config = yaml_conf(conf_path)
+    data_base_dir = read_conf(yaml_config, 'data_base_dir')
+    read_dirs = [os.path.join(data_base_dir, '2404'), os.path.join(data_base_dir, '2405')]
+
+    for read_dir in read_dirs:
+        dir_time = time.time()
+        for root, dirs, files in os.walk(read_dir):
+            for file in files:
+                try:
+                    file_dir = os.path.basename(root)
+
+                    read_csv = root + os.sep + file
+                    df = pd.read_csv(read_csv, header=None)
+                    mesurepoint_maps = generate_mesurepoint_maps(f'conf/测点表-{file_dir}.xlsx')
+                    add_table(mesurepoint_maps.keys())
+
+                    with multiprocessing.Pool(5) as pool:
+                        pool.starmap(generate_scada_data,
+                                     [(df, mesurepoint_maps, changzhan, wind_code_name_map) for changzhan in
+                                      mesurepoint_maps.keys()])
+
+                    os.remove(read_csv)
+                except:
+                    logger.error(traceback.format_exc())
+                logger.info(f'SCADA执行完:{file_dir}/{file}耗时:{time.time() - dir_time}')
+        logger.info(f'{read_dir}执行总耗时:{time.time() - dir_time}')
+    logger.info(f'SCADA执行总耗时:{time.time() - total_begin}')

+ 289 - 0
parse_warn_fault_data.py

@@ -0,0 +1,289 @@
+"""
+读取104规约返回的数据,并标准化到临时表中
+"""
+import multiprocessing
+import os.path
+import time
+import warnings
+from datetime import datetime, timedelta
+
+import pandas as pd
+
+from service import plt_service, trans_service
+from utils.conf.read_conf import yaml_conf, read_conf
+from utils.log.trans_log import logger
+
+warnings.filterwarnings('ignore')
+
+
+def is_file_modified_recently(file_path, minutes=15):
+    """
+    检查文件最后修改时间是否在指定的分钟数内
+
+    参数:
+        file_path: 文件路径
+        minutes: 检查的分钟数(默认为15分钟)
+
+    返回:
+        bool: True表示在指定时间内修改过,False表示超过指定时间未修改
+    """
+    if not os.path.exists(file_path):
+        raise FileNotFoundError(f"文件不存在: {file_path}")
+
+    # 获取文件最后修改时间(时间戳)
+    mod_time = os.path.getmtime(file_path)
+
+    # 转换为datetime对象
+    mod_datetime = datetime.fromtimestamp(mod_time)
+    logger.info(f'文件修改时间:{mod_datetime}')
+    # 计算当前时间与修改时间的差
+    time_diff = datetime.now() - mod_datetime
+
+    # 检查是否在指定分钟内
+    return time_diff <= timedelta(minutes=minutes)
+
+
+def generate_mesurepoint_maps(file_path):
+    df = pd.read_excel(file_path)
+
+    wind_maps = dict()
+    for _, data in df.iterrows():
+        shunxuhao = int(data['顺序号']) + 1
+        changzhan = data['场站标准化编号']
+        wind_no = data['风机号']
+        en_name = data['标准化英文']
+        if changzhan in wind_maps.keys():
+            if wind_no in wind_maps[changzhan].keys():
+                wind_maps[changzhan][wind_no][shunxuhao] = en_name
+            else:
+                wind_maps[changzhan][wind_no] = {shunxuhao: en_name}
+        else:
+            wind_maps[changzhan] = {wind_no: {shunxuhao: en_name}}
+
+    return wind_maps
+
+
+def generate_warn_falut_code_maps(file_path):
+    df = pd.read_excel(file_path)
+    df['主控ID'] = df['主控ID'].str.strip()
+    df['状态编码'] = df['状态编码'].astype(int)
+    df['SC中文描述'] = df['SC中文描述'].str.strip()
+    df['告警等级'] = df['告警等级'].str.strip()
+    df['告警等级'] = df['告警等级'].fillna("告警信息")
+
+    result_map = dict()
+    for index, row in df.iterrows():
+        controller_id = row['主控ID'].strip()
+        status_code = int(row['状态编码'])
+        cn_des = row['SC中文描述']
+        level = row['告警等级']
+        if controller_id in result_map.keys():
+            result_map[controller_id][status_code] = (cn_des, level)
+        else:
+            result_map[controller_id] = {status_code: (cn_des, level)}
+
+    return result_map
+
+
+def generate_warn_falut_maps(file_path):
+    df = pd.read_excel(file_path)
+
+    warn_fault_maps = dict()
+    for _, data in df.iterrows():
+        seq_no = int(data['顺序号']) + 1
+        changzhan = data['场站标准化编号']
+        wind_no = data['风机号']
+        if changzhan in warn_fault_maps.keys():
+            if wind_no in warn_fault_maps[changzhan].keys():
+                warn_fault_maps[changzhan][wind_no].append(seq_no)
+            else:
+                warn_fault_maps[changzhan][wind_no] = [seq_no]
+        else:
+            warn_fault_maps[changzhan] = {wind_no: [seq_no]}
+
+    return warn_fault_maps
+
+
+def generate_mc_version_maps(file_path):
+    df = pd.read_excel(file_path)
+
+    mc_version_maps = dict()
+    for _, data in df.iterrows():
+        changzhan = data['场站标准化编号'].strip()
+        wind_no = data['风机号']
+        mc_versioin = data['主控版本'].strip()
+        if changzhan in mc_version_maps.keys():
+            mc_version_maps[changzhan][wind_no] = mc_versioin
+        else:
+            mc_version_maps[changzhan] = {wind_no: mc_versioin}
+
+    return mc_version_maps
+
+
+def exists_windno_seq_fault(changzhan):
+    exists_data_dict = trans_service.exists_windno_seq_fault(changzhan)
+    return exists_data_dict
+
+
+def generate_warn_fault_data(df, warn_fault_point_maps, warn_falut_code_maps, mc_vesion_maps, changzhan,
+                             wind_code_name_map):
+    wind_df = pd.DataFrame()
+
+    if changzhan not in mc_vesion_maps.keys():
+        print(f'{changzhan} not in mc_vesion_maps')
+        return None
+
+    max_time = df[0].max()
+
+    wind_maps, _ = plt_service.get_wind_info(changzhan, False)
+
+    wind_nos = warn_fault_point_maps[changzhan].keys()
+    wind_seq_no_map = warn_fault_point_maps[changzhan]
+    exists_data_dict = exists_windno_seq_fault(changzhan)
+
+    for wind_no in wind_nos:
+        seq_nos = list(wind_seq_no_map[wind_no])
+        seq_nos.insert(0, 0)
+        now_df = df[seq_nos]
+        now_df.set_index(keys=0, inplace=True)
+        now_df = now_df.T
+        cols = list(now_df.columns)
+        # 设置KEY 为 顺序号_错误码
+        seq_no_dict = dict()
+        # 循环每行的数据
+        for index, row in now_df.iterrows():
+            values = [int(i) for i in row.values]
+            seq_no = index
+            is_first = True
+            for i in range(len(values)):
+                key = f'{seq_no}_{values[i]}'
+                if values[i] == 0 or values[i] == 309001:
+                    # 如果当前数据存在错误,则更新字典,否则更新表数据
+                    if key in seq_no_dict.keys():
+                        for data in seq_no_dict[key]:
+                            if data[4] is None:
+                                data[4] = cols[i]
+                    else:
+                        # TODO 写数据库
+                        if is_first:
+                            trans_service.update_warn_fault_exist_data(changzhan, seq_no, cols[i])
+                            is_first = False
+
+                elif values[i] > 0:
+                    if key not in seq_no_dict.keys():
+                        seq_no_dict[key] = [wind_no, seq_no, values[i], cols[i], None]
+
+        # result = [sublist for key in seq_no_dict for sublist in seq_no_dict[key]]
+        result = seq_no_dict.values()
+        result_df = pd.DataFrame(result,
+                                 columns=['wind_turbine_name', 'seq_no', 'fault_code', 'begin_time', 'end_time'])
+
+        result_df['mc_version'] = result_df['wind_turbine_name'].apply(lambda x: mc_vesion_maps[changzhan].get(x, None))
+        result_df.dropna(subset=['mc_version'], inplace=True)
+
+        def get_fault_dict(x, index):
+            if x['mc_version'] not in warn_falut_code_maps.keys():
+                return None
+
+            if x['fault_code'] not in warn_falut_code_maps[x['mc_version']].keys():
+                return None
+            return warn_falut_code_maps[x['mc_version']][x['fault_code']][index]
+
+        result_df['fault_detail'] = result_df[['mc_version', 'fault_code']].apply(get_fault_dict, args=(0,), axis=1)
+        result_df['fault_level'] = result_df[['mc_version', 'fault_code']].apply(get_fault_dict, args=(1,), axis=1)
+
+        result_df.dropna(subset=['fault_detail', 'fault_level'], how='all', inplace=True)
+        result_df['begin_time'] = pd.to_datetime(result_df['begin_time'], errors='coerce')
+        result_df['end_time'] = pd.to_datetime(result_df['end_time'], errors='coerce')
+        result_df['time_diff'] = (result_df['end_time'] - result_df['begin_time']).dt.total_seconds()
+
+        result_df['wind_turbine_name'] = result_df['wind_turbine_name'].astype(str)
+        result_df['wind_turbine_number'] = result_df['wind_turbine_name'].map(wind_maps)
+
+        wind_df = pd.concat([wind_df, result_df])
+    # wind_df.to_csv(f'tmp/104/warn_fault/{changzhan}.csv', index=False)
+
+    warn_df = wind_df[wind_df['fault_level'] != '故障']
+    fault_df = wind_df[wind_df['fault_level'] == '故障']
+
+    # exists_data_dict
+
+    def del_exist_data(df: pd.DataFrame(), exists_data: list):
+        df['key_no'] = df.apply(lambda x: f"{x['wind_turbine_name']}_{x['seq_no']}_{x['fault_code']}", axis=1)
+        df = df[~((df['time_diff'].isna()) & (df['key_no'].isin(exists_data)))]
+        del df['key_no']
+        return df
+
+    warn_df = del_exist_data(warn_df, exists_data_dict['warn'])
+    fault_df = del_exist_data(fault_df, exists_data_dict['fault'])
+
+    warn_df.sort_values(by='begin_time', inplace=True)
+    fault_df.sort_values(by='begin_time', inplace=True)
+
+    if not warn_df.empty:
+        trans_service.save_df_to_db(f'{changzhan}_warn', warn_df)
+        warn_max_date = warn_df['begin_time'].max()
+        add_date_str = warn_max_date.strftime('%Y-%m-%d')
+        warn_last_date_str = warn_max_date.strftime('%Y-%m-%d %H:%M:%S')
+        # wind_farm_code, wind_farm_name, add_date, trans_type, count, latest_data_time
+        trans_service.update_wind_farm_day_count(changzhan, wind_code_name_map.get(changzhan, ''), add_date_str,
+                                                 'warn', warn_df.shape[0], warn_last_date_str, 1)
+
+    if not fault_df.empty:
+        trans_service.save_df_to_db(f'{changzhan}_fault', fault_df)
+        fault_max_date = fault_df['begin_time'].max()
+        add_date_str = fault_max_date.strftime('%Y-%m-%d')
+        fault_last_date_str = fault_max_date.strftime('%Y-%m-%d %H:%M:%S')
+        trans_service.update_wind_farm_day_count(changzhan, wind_code_name_map.get(changzhan, ''), add_date_str,
+                                                 'fault', fault_df.shape[0], fault_last_date_str, 1)
+
+    trans_service.update_warn_fault_update_time(date_str,max_time)
+
+
+if __name__ == '__main__':
+    time.sleep(40)
+    total_begin = time.time()
+    begin = time.time()
+
+    date_str = datetime.now().strftime('%Y_%m_%d')
+
+    wind_code_name_map = plt_service.get_all_wind_by_company_code('COM00002')
+
+    conf_path = os.path.abspath(f"./conf/config.yaml")
+    yaml_config = yaml_conf(conf_path)
+    data_base_dir = read_conf(yaml_config, 'data_base_dir')
+    read_dir = os.path.join(data_base_dir, '2406')
+
+    # 故障报警测点
+    warn_fault_point_maps = generate_warn_falut_maps('conf/故障报警测点-2406.xlsx')
+    # 主控代码
+    warn_falut_code_maps = generate_warn_falut_code_maps('conf/主控故障代码表-2406.xlsx')
+    # 主控版本
+    mc_vesion_maps = generate_mc_version_maps('conf/主控版本-2406.xlsx')
+    for root, dirs, files in os.walk(read_dir):
+        files.sort()
+        for file in files:
+            exec_begin = time.time()
+            file_dir = os.path.basename(root)
+
+            read_csv = root + os.sep + file
+            df = pd.read_csv(read_csv, header=None)
+
+            begin = time.time()
+            with multiprocessing.Pool(5) as pool:
+                pool.starmap(generate_warn_fault_data,
+                             [(df, warn_fault_point_maps, warn_falut_code_maps, mc_vesion_maps, changzhan,
+                               wind_code_name_map)
+                              for changzhan in
+                              warn_fault_point_maps.keys()])
+
+            # TODO 保存最近一条数据到临时文件中以供下次使用
+            # last_data.to_csv(file_path, header=False, index=False)
+
+            # new_file = read_csv.replace('data/2406', 'data_bak/2406 ')
+            # shutil.copy(read_csv, new_file)
+            os.remove(read_csv)
+
+            logger.info(
+                f'故障报警执行完:{file_dir}/{file}耗时:{time.time() - exec_begin},总耗时:{time.time() - total_begin}')
+    logger.info(f'故障报警总耗时:{time.time() - total_begin}')

+ 8 - 0
requirements.txt

@@ -0,0 +1,8 @@
+numpy==2.2.3
+pandas==2.2.3
+psutil==6.0.0
+PyMySQL==1.1.0
+PyYAML==6.0.2
+SQLAlchemy==2.0.30
+xlrd
+openpyxl

+ 0 - 0
service/__init__.py


+ 5 - 0
service/common_connect.py

@@ -0,0 +1,5 @@
+from utils.db.ConnectMysql import ConnectMysql
+
+plt = ConnectMysql("plt")
+
+trans = ConnectMysql("trans")

+ 45 - 0
service/plt_service.py

@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/6/7
+# @Author  : 魏志亮
+
+from service.common_connect import plt
+
+
+def get_wind_info(field_code, need_rated_param=True):
+    query_sql = """
+    SELECT t.engine_code,t.engine_name,t.rated_capacity,a.rated_cut_out_windspeed 
+    from wind_engine_group t LEFT JOIN wind_engine_mill a on t.mill_type_code  = a.mill_type_code 
+    where t.field_code = %s and t.del_state = 0
+    """
+    dict_datas = plt.execute(query_sql, (field_code,))
+    wind_result = dict()
+    power_result = dict()
+    for data in dict_datas:
+        wind_result[str(data['engine_name'])] = str(data['engine_code'])
+        if need_rated_param:
+            power_result[str(data['engine_code'])] = (
+                float(data['rated_capacity']), float(data['rated_cut_out_windspeed']))
+    return wind_result, power_result
+
+
+def get_all_wind():
+    query_sql = """
+    SELECT t.code_number,t.code_name from wind_relation t where t.type = 'field' 
+    """
+    return plt.execute(query_sql)
+
+
+def get_all_wind_by_company_code(company_code):
+    query_sql = f"""
+    SELECT t.code_number,t.code_name from wind_relation t where t.parent_code = '{company_code}' and t.type = 'field' 
+    """
+    datas = plt.execute(query_sql)
+    result = dict()
+    for data in datas:
+        result[data['code_number']] = str(data['code_name'])
+
+    return result
+
+
+if __name__ == '__main__':
+    print(get_all_wind_by_company_code('COM00002'))

+ 254 - 0
service/trans_service.py

@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/6/7
+# @Author  : 魏志亮
+import traceback
+
+import pandas as pd
+
+from service.common_connect import trans
+from utils.log.trans_log import logger
+
+
+def create_tmp_table(table_name):
+    create_sql = f"""
+    CREATE TABLE `{table_name}` (
+  `wind_turbine_number` varchar(20) DEFAULT NULL COMMENT '风机编号',
+  `wind_turbine_name` varchar(20) DEFAULT NULL COMMENT '风机原始名称',
+  `time_stamp` datetime NOT NULL COMMENT '时间戳',
+  `active_power` double DEFAULT NULL COMMENT '有功功率',
+  `rotor_speed` double DEFAULT NULL COMMENT '风轮转速',
+  `generator_speed` double DEFAULT NULL COMMENT '发电机转速',
+  `wind_velocity` double DEFAULT NULL COMMENT '风速',
+  `pitch_angle_blade_1` double DEFAULT NULL COMMENT '桨距角1',
+  `pitch_angle_blade_2` double DEFAULT NULL COMMENT '桨距角2',
+  `pitch_angle_blade_3` double DEFAULT NULL COMMENT '桨距角3',
+  `cabin_position` double DEFAULT NULL COMMENT '机舱位置',
+  `true_wind_direction` double DEFAULT NULL COMMENT '绝对风向',
+  `yaw_error1` double DEFAULT NULL COMMENT '对风角度',
+  `set_value_of_active_power` double DEFAULT NULL COMMENT '有功功率设定值',
+  `gearbox_oil_temperature` double DEFAULT NULL COMMENT '齿轮箱油温',
+  `generatordrive_end_bearing_temperature` double DEFAULT NULL COMMENT '发电机驱动端轴承温度',
+  `generatornon_drive_end_bearing_temperature` double DEFAULT NULL COMMENT '发电机非驱动端轴承温度',
+  `cabin_temperature` double DEFAULT NULL COMMENT '机舱内温度',
+  `twisted_cable_angle` double DEFAULT NULL COMMENT '扭缆角度',
+  `front_back_vibration_of_the_cabin` double DEFAULT NULL COMMENT '机舱前后振动',
+  `side_to_side_vibration_of_the_cabin` double DEFAULT NULL COMMENT '机舱左右振动',
+  `actual_torque` double DEFAULT NULL COMMENT '实际力矩',
+  `given_torque` double DEFAULT NULL COMMENT '给定力矩',
+  `clockwise_yaw_count` double DEFAULT NULL COMMENT '顺时针偏航次数',
+  `counterclockwise_yaw_count` double DEFAULT NULL COMMENT '逆时针偏航次数',
+  `unusable` double DEFAULT NULL COMMENT '不可利用',
+  `power_curve_available` double DEFAULT NULL COMMENT '功率曲线可用',
+  `required_gearbox_speed` double DEFAULT NULL COMMENT '齿轮箱转速',
+  `inverter_speed_master_control` double DEFAULT NULL COMMENT '变频器转速(主控)',
+  `outside_cabin_temperature` double DEFAULT NULL COMMENT '环境温度',
+  `main_bearing_temperature` double DEFAULT NULL COMMENT '主轴承轴承温度',
+  `gearbox_high_speed_shaft_bearing_temperature` double DEFAULT NULL COMMENT '齿轮箱高速轴轴承温度',
+  `gearboxmedium_speed_shaftbearing_temperature` double DEFAULT NULL COMMENT '齿轮箱中速轴轴承温度',
+  `gearbox_low_speed_shaft_bearing_temperature` double DEFAULT NULL COMMENT '齿轮箱低速轴轴承温度',
+  `generator_winding1_temperature` double DEFAULT NULL COMMENT '发电机绕组1温度',
+  `generator_winding2_temperature` double DEFAULT NULL COMMENT '发电机绕组2温度',
+  `generator_winding3_temperature` double DEFAULT NULL COMMENT '发电机绕组3温度',
+  `wind_turbine_status` double DEFAULT NULL COMMENT '风机状态1',
+  `wind_turbine_status2` double DEFAULT NULL COMMENT '风机状态2',
+  `turbulence_intensity` double DEFAULT NULL COMMENT '湍流强度'
+  )
+    """
+    trans.execute(create_sql)
+
+
+def boolean_table_exists(table_name):
+    table_sql = f"""
+    select count(1) as count from information_schema.tables where table_name = '{table_name}'
+    """
+    data = trans.execute(table_sql)[0]
+
+    if int(data['count']) == 0:
+        return False
+    return True
+
+
+def add_partition(table_name, pname, date_str):
+    try:
+        sql = f"""
+        ALTER TABLE {table_name} REORGANIZE PARTITION pmax INTO (
+            PARTITION {pname} VALUES LESS THAN ('{date_str}'),
+            PARTITION pmax VALUES LESS THAN (MAXVALUE)
+        );
+        """
+        trans.execute(sql)
+        logger.info(f"添加{table_name}分区{pname}成功")
+    except:
+        logger.error(traceback.format_exc())
+
+
+def delelet_partition(table_name, pmonth):
+    pname = f'p{str(pmonth.year) + str(pmonth.month).zfill(2)}'
+
+    exists_partition_sql = f"""
+    SELECT count(1) from INFORMATION_SCHEMA.`PARTITIONS` t  where t.TABLE_NAME = '{table_name}' and t.PARTITION_NAME = '{pname}'
+    """
+    data = trans.execute(exists_partition_sql)[0]
+    if data > 0:
+        del_sql = f"""
+        ALTER TABLE {table_name} DROP PARTITION {pname}
+        """
+        trans.execute(del_sql)
+        logger.info(f"删除{table_name}分区{pname}成功")
+
+    else:
+        logger.info(f"删除{table_name}分区{pname}不存在")
+
+
+def get_all_partitioned_tables() -> list:
+    all_tables_sql = """
+    SELECT t.TABLE_NAME FROM INFORMATION_SCHEMA.`TABLES` t where t.CREATE_OPTIONS = 'partitioned'
+    """
+    return trans.execute(all_tables_sql)
+
+
+def save_df_to_db(table_name: str, df: pd.DataFrame(), batch_count=1000):
+    try:
+        if 'index' in df.columns:
+            del df['index']
+        trans.execute_df_save(df, table_name, batch_count)
+    except Exception as e:
+        logger.error(traceback.format_exc())
+        raise Exception(str(e))
+
+
+def load_data_local(table_name, df):
+    columns_str = 'wind_turbine_number,wind_turbine_name,time_stamp,active_power,rotor_speed,generator_speed,wind_velocity,pitch_angle_blade_1,pitch_angle_blade_2,pitch_angle_blade_3,cabin_position,true_wind_direction,yaw_error1,set_value_of_active_power,gearbox_oil_temperature,generatordrive_end_bearing_temperature,generatornon_drive_end_bearing_temperature,cabin_temperature,twisted_cable_angle,front_back_vibration_of_the_cabin,side_to_side_vibration_of_the_cabin,actual_torque,given_torque,clockwise_yaw_count,counterclockwise_yaw_count,unusable,power_curve_available,required_gearbox_speed,inverter_speed_master_control,outside_cabin_temperature,main_bearing_temperature,gearbox_high_speed_shaft_bearing_temperature,gearboxmedium_speed_shaftbearing_temperature,gearbox_low_speed_shaft_bearing_temperature,generator_winding1_temperature,generator_winding2_temperature,generator_winding3_temperature,wind_turbine_status,wind_turbine_status2,turbulence_intensity,lab,year,month,day,year_month'
+    cols = columns_str.split(',')
+    print(cols)
+    df = df[cols]
+    # trans.execute_df_save(df, table_name, batch_count)
+    trans.safe_load_data_local(df, table_name)
+
+
+def drop_table(table_name):
+    drop_sql = f"DROP TABLE `{table_name}`"
+    try:
+        trans.execute(drop_sql)
+    except:
+        logger.error(traceback.format_exc())
+
+
+def get_yesterday_tables(yesterday):
+    query_sql = f"""
+    select * from wind_farm_day_count where add_date = '{yesterday}' and sync_status = 0
+    """
+    return trans.execute(query_sql)
+
+
+def update_sync(id):
+    update_sql = f"update wind_farm_day_count set sync_status = 1 where id = {id}"
+    trans.execute(update_sql)
+
+
+def update_wind_farm_day_count(wind_farm_code, wind_farm_name, add_date, trans_type, count, latest_data_time,
+                               sync_status=0):
+    select_sql = f"SELECT * from wind_farm_day_count  WHERE `wind_farm_code` = '{wind_farm_code}' and `add_date` = '{add_date}' and `type` = '{trans_type}' "
+    result = trans.execute(select_sql)
+    if result:
+        id = result[0]['id']
+        update_sql = f"update wind_farm_day_count set count = count + {count}, latest_data_time = '{latest_data_time}' where id = {id}"
+        trans.execute(update_sql)
+    else:
+        insert_sql = f"""
+        INSERT INTO `wind_farm_day_count` (
+        `wind_farm_code`,
+        `wind_farm_name`,
+        `add_date`,
+        `type`,
+        `count`,
+        `sync_status`,
+        `del_status`,
+        `latest_data_time`
+    )
+        VALUES
+        (
+            '{wind_farm_code}',
+            '{wind_farm_name}',
+            '{add_date}',
+            '{trans_type}',
+            '{count}',
+            '{sync_status}',
+            '0',
+            '{latest_data_time}'
+        )
+        """
+        trans.execute(insert_sql)
+
+
+def get_sys_conf_by_key(type, param_key, default_value=None):
+    sql = f"SELECT * from sys_conf t where t.type ='{type}'  and t.param_key = '{param_key}' and status = 1"
+    datas = trans.execute(sql)
+    if isinstance(datas, tuple):
+        return default_value
+    else:
+        return datas[0]['param_value']
+
+
+def get_sys_conf(type) -> dict:
+    sql = f"SELECT * from sys_conf t where t.type ='{type}' and status = 1"
+    datas = trans.execute(sql)
+    if isinstance(datas, tuple):
+        return {}
+    else:
+        result_dict = dict()
+        for data in datas:
+            result_dict[data['param_key']] = data['param_value']
+        return result_dict
+
+
+def read_data_from_table(table_name):
+    df = pd.read_sql_table(con=trans.get_engine(), table_name=table_name)
+    return df
+
+
+def update_warn_fault_exist_data(changzhan, seq_no, end_time):
+    updata_tables = [f'{changzhan}_warn', f'{changzhan}_fault']
+
+    for table_name in updata_tables:
+        update_sql = f"""
+        update {table_name} set end_time = '{end_time}', time_diff = TIMESTAMPDIFF(SECOND, begin_time,'{end_time}') 
+        where seq_no = {seq_no} and end_time is null
+        """
+        trans.execute(update_sql)
+        logger.info(f"更新{changzhan}故障顺序号{seq_no}成功")
+
+
+def update_expired_data(table_type, exists_date):
+    update_expired_sql = f"""
+    update wind_farm_day_count set del_status = 1 where type = '{table_type}' and add_date < '{exists_date}'
+    """
+    trans.execute(update_expired_sql)
+    logger.info(f"删除类型{table_type},截止日期{exists_date}成功")
+
+
+def exists_windno_seq_fault(changzhan):
+    types = ['warn', 'fault']
+    result_dict = dict(list())
+    for type in types:
+        result_dict[type] = list()
+        query_sql = f"select * from {changzhan}_{type} where time_diff is null"
+        fault_datas = trans.execute(query_sql)
+        if isinstance(fault_datas, tuple):
+            result_dict[type] = []
+        else:
+            for data in fault_datas:
+                # t.wind_turbine_name,t.seq_no,t.fault_code
+                result_dict[type].append(f"{data['wind_turbine_name']}_{data['seq_no']}_{data['fault_code']}")
+
+    return result_dict
+
+
+def update_warn_fault_update_time(date_str, max_time):
+    sql = f"update wind_farm_day_count set update_time = '{max_time}' where add_date = '{date_str}' and type in ('warn','fault')"
+    trans.execute(sql)
+    logger.info(f"更新{date_str}的故障报警到当前时间")
+
+
+if __name__ == '__main__':
+    update_wind_farm_day_count('1', '1', '2025-04010', 100)

+ 0 - 0
tmp/__init__.py


+ 15 - 0
tmp/add_yuxian_fault.py

@@ -0,0 +1,15 @@
+import pandas as pd
+
+from service import trans_service
+
+file_path = r'C:\Users\wzl\Desktop\fault.csv'
+
+df = pd.read_csv(file_path)
+
+print(df)
+
+df['begin_time'] = pd.to_datetime(df['begin_time'])
+
+df = df[df['begin_time'] <= '2025-04-24 10:09:12']
+
+trans_service.save_df_to_db('WOF35800082_fault', df)

+ 33 - 0
tmp/cedian-extract_分钟.py

@@ -0,0 +1,33 @@
+import os
+
+import pandas as pd
+
+
+def add_minute_table(df):
+    del df['历史采样表名']
+    del df['历史采样域名']
+
+    min_table_path = r'C:\Users\wzl\Desktop\中广核104测点\分钟级表-字段.csv'
+    min_df = pd.read_csv(min_table_path, encoding='gbk', usecols=['遥测ID', '历史采样表名', '历史采样域名'])
+
+    min_df['遥测ID'] = min_df['遥测ID'].apply(lambda x: x.replace('遥测定义表 ', '').replace('遥测值', '').strip())
+    min_df.rename(columns={'遥测ID': '遥测名称'}, inplace=True)
+
+    df = df.merge(min_df, on='遥测名称', how='left')
+    return df
+
+
+if __name__ == '__main__':
+    read_file = r'C:\Users\wzl\Desktop\中广核104测点\0416部署需要\最终测点配置.xlsx'
+    df = pd.read_excel(read_file)
+    # df = add_minute_table(df)
+    # df.to_excel('最终测点配置.xlsx', index=False)
+
+    wind_names = df['场站'].unique()
+
+    for wind_name in wind_names:
+        now_df = df[df['场站'] == wind_name]
+        port = now_df['端口'].unique()[0]
+        os.makedirs(str(port), exist_ok=True)
+        now_df.sort_values(by=['风机号', '测点'], inplace=True)
+        now_df.to_csv(os.path.join(str(port), wind_name + '.csv'))

+ 114 - 0
tmp/cedian.py

@@ -0,0 +1,114 @@
+import os.path
+
+import pandas as pd
+
+if __name__ == '__main__':
+    read_file = r'C:\Users\wzl\Desktop\中广核104测点\12CZYC1.csv'
+    all_df = pd.read_csv(read_file, encoding='gbk')
+
+    df = all_df[['遥测名称', 'Unnamed: 1', '遥测别名']]
+    df.rename(columns={'Unnamed: 1': '标准化中文'}, inplace=True)
+    df_2404 = pd.read_csv(r'C:\Users\wzl\Desktop\中广核104测点\2404\2404测点.csv', encoding='utf8')
+    df_2405 = pd.read_csv(r'C:\Users\wzl\Desktop\中广核104测点\2405\2405测点.csv', encoding='utf8')
+    df_2404 = df_2404[['遥测ID号', '标准化中文', 'en_name']]
+    df_2405 = df_2405[['遥测ID号', '标准化中文', 'en_name']]
+
+    biaozhunhua_str = """
+舱内温度	机舱内温度	cabin_temperature
+舱外温度	环境温度	outside_cabin_temperature
+齿轮箱油池温度	齿轮箱油温	gearbox_oil_temperature
+齿轮箱中速轴非驱动端轴承温度	齿轮箱中速轴轴承温度	gearboxmedium_speed_shaftbearing_temperature
+发电机定子U相线圈温度	发电机绕组1温度	generator_winding1_temperature
+发电机定子V相线圈温度	发电机绕组2温度	generator_winding2_temperature
+发电机定子W相线圈温度	发电机绕组3温度	generator_winding3_temperature
+发电机非驱动端轴承温度	发电机非驱动端轴承温度	generatornon_drive_end_bearing_temperature
+发电机驱动端轴承温度	发电机驱动端轴承温度	generatordrive_end_bearing_temperature
+发电机转速	发电机转速	generator_speed
+机舱侧向振动(已滤波)	机舱左右振动	side_to_side_vibration_of_the_cabin
+机舱角度	机舱位置	cabin_position
+机舱中轴线与风向夹角	对风角度	yaw_error1
+机舱轴向振动(已滤波)	机舱前后振动	front_back_vibration_of_the_cabin
+主轴转速	风轮转速	rotor_speed
+    """
+
+    biaozhuan_datas = [i.strip().split('\t') for i in biaozhunhua_str.split('\n') if i.strip()]
+    biaozhun_cn = {}
+    for i in biaozhuan_datas:
+        biaozhun_cn[i[0]] = i[1]
+
+    df['标准化中文'] = df['标准化中文'].map(biaozhun_cn).fillna(df['标准化中文'])
+    df_24port = pd.concat([df_2404, df_2405])
+    df_24port.rename(columns={'遥测ID号': '遥测名称'}, inplace=True)
+    biaozhun_cn_map = {}
+    biaozhun_en_map = {}
+    for k, c, e in zip(df_24port['遥测名称'], df_24port['标准化中文'], df_24port['en_name']):
+        biaozhun_cn_map[k] = c
+        biaozhun_en_map[c] = e
+
+    df['标准化中文'] = df['遥测名称'].map(biaozhun_cn_map).fillna(df['标准化中文'])
+    df['en_name'] = df['标准化中文'].map(biaozhun_en_map)
+    df.dropna(subset='标准化中文', inplace=True)
+    df.dropna(subset='遥测别名', inplace=True)
+    df['场站'] = df['遥测别名'].apply(lambda x: x.split('.')[0])
+    df['风机号'] = df['遥测别名'].apply(lambda x: x.split('.')[2])
+    df['测点'] = df['遥测别名'].apply(lambda x: '.'.join(x.split('.')[3:]))
+
+    changzhan_map = {
+        'FFFD': '富风',
+        'MJLFD': '马家梁',
+        'PLPFD': '坡底',
+        'SLRY': '石楼',
+        'SSLF20219': '贺家沟',
+        'SXGJ': '古交',
+        'SXRC': '芮城',
+        'SXYX': '盂县',
+        'SXYY': '右玉',
+        'YCPL': '平陆',
+        'YNJS': '阳曲',
+        'YQXP': '西潘'
+    }
+
+    port_map = {
+        '富风': 2405,
+        '马家梁': 2405,
+        '坡底': 2405,
+        '石楼': 2404,
+        '贺家沟': 2405,
+        '古交': 2404,
+        '芮城': 2404,
+        '盂县': 2404,
+        '右玉': 2404,
+        '平陆': 2404,
+        '阳曲': 2405,
+        '西潘': 2405
+    }
+
+    df['场站'] = df['场站'].map(changzhan_map)
+    df['端口'] = df['场站'].map(port_map)
+
+    df = df[~((df['场站'] == '马家梁') &
+              (df['遥测别名'].str.contains('WNAC.TemNacelleCab'))
+              & (df['风机号'].isin(['WTG' + str(i).zfill(3) for i in range(26, 50)])))]
+
+    df = df[~((df['场站'] == '盂县') &
+              (df['遥测别名'].str.contains('WNAC.WindDirectionInstant'))
+              & (df['风机号'].isin(['WTG' + str(i).zfill(3) for i in range(1, 57)])))]
+
+    min_table_path = r'C:\Users\wzl\Desktop\中广核104测点\分钟级表-字段.csv'
+    min_df = pd.read_csv(min_table_path, encoding='gbk', usecols=['遥测ID', '历史采样表名', '历史采样域名'])
+
+    min_df['遥测ID'] = min_df['遥测ID'].apply(lambda x: x.replace('遥测定义表 ', '').replace('遥测值', '').strip())
+    min_df.rename(columns={'遥测ID': '遥测名称'}, inplace=True)
+
+    df = df.merge(min_df, on='遥测名称', how='left')
+
+    df.to_excel('最终测点配置.xlsx', index=False)
+
+    wind_names = df['场站'].unique()
+
+    for wind_name in wind_names:
+        now_df = df[df['场站'] == wind_name]
+        port = now_df['端口'].unique()[0]
+        os.makedirs(str(port), exist_ok=True)
+        now_df.sort_values(by=['风机号', '测点'], inplace=True)
+        now_df.to_csv(os.path.join(str(port), wind_name + '.csv'))

+ 39 - 0
tmp/delete_repeat_data.py

@@ -0,0 +1,39 @@
+from service import plt_service
+
+wind_farms = {
+    # "WOF35900004": "平陆风电场",
+    # "WOF35100072": "阳曲风电场",
+    "WOF35100073": "古交风电场",
+    "WOF35200074": "马家梁风电场",
+    "WOF35400075": "太谷风电场",
+    "WOF35900076": "坡底风电场",
+    "WOF35300077": "西潘风电场",
+    "WOF35900078": "芮城风电场",
+    "WOF34900079": "右玉风光互补电站",
+    "WOF35800080": "贺家沟",
+    "WOF35800081": "石楼风电场",
+    "WOF35800082": "盂县风光互补电站"
+}
+
+for k, v in wind_farms.items():
+    wind_infos, _ = plt_service.get_wind_info(k, False)
+    for type in ['second', 'minute']:
+        for name, wind_code in wind_infos.items():
+            print('-- ', v, type, wind_code)
+
+            sql = f"""
+            SET tidb_mem_quota_query = 8589934592;
+            DELETE t FROM {k}_{type} t 
+            JOIN(
+            SELECT wind_turbine_number,time_stamp, ROW_NUMBER() OVER (PARTITION BY wind_turbine_number,time_stamp ORDER BY wind_turbine_number,time_stamp) AS rn
+                FROM {k}_{type} a
+            WHERE  
+            a.wind_turbine_number = '{wind_code}'
+            and a.time_stamp in (
+            SELECT time_stamp from {k}_{type} PARTITION(p202504) b where b.time_stamp BETWEEN '2025-04-01 00:00:00' and '2025-04-30 23:59:59'
+            and b.wind_turbine_number = '{wind_code}'
+            GROUP BY b.time_stamp HAVING count(1) > 1
+            )) t2 on t.time_stamp = t2.time_stamp and t.wind_turbine_number = t2.wind_turbine_number where t2.rn > 1;
+            """
+            print(sql)
+            # trans.execute(sql)

+ 46 - 0
tmp/diff_2_104_file.py

@@ -0,0 +1,46 @@
+import pandas as pd
+
+if __name__ == '__main__':
+    read_file = r'C:\Users\wzl\Desktop\中广核104测点\0416部署需要\最终测点配置.xlsx'
+    df = pd.read_excel(read_file)
+
+    read_file = r'C:\Users\wzl\Desktop\中广核104测点\12CZYC1.csv'
+    ori_df = pd.read_csv(read_file, encoding='gbk', usecols=['遥测名称', '遥测别名'])
+
+    ori_df['测点'] = ori_df['遥测别名'].apply(lambda x: '.'.join(x.split('.')[3:]))
+
+    wind_names = df['场站'].unique()
+
+    result_dict_2404 = dict()
+    result_dict_2405 = dict()
+    for wind_name in wind_names:
+        ori_now_df = ori_df[ori_df['遥测名称'].str.contains(wind_name)]
+        now_df = df[df['场站'] == wind_name]
+        port = int(now_df['端口'].values[0])
+        cedianers = now_df['测点'].unique()
+        for cedian in cedianers:
+            now_count = now_df[now_df['测点'] == cedian].shape[0]
+            ori_count = ori_now_df[ori_now_df['测点'] == cedian].shape[0]
+            diff = ori_count - now_count
+            if port == 2404:
+                if wind_name not in result_dict_2404.keys():
+                    result_dict_2404[wind_name] = dict()
+
+                result_dict_2404[wind_name][cedian] = diff
+            else:
+                if wind_name not in result_dict_2405.keys():
+                    result_dict_2405[wind_name] = dict()
+
+                result_dict_2405[wind_name][cedian] = diff
+
+    print('*' * 50)
+    for win_name, diff_dict in result_dict_2404.items():
+        print(win_name)
+        for cedian, diff in diff_dict.items():
+            print(cedian, diff)
+
+    print('*' * 50)
+    for win_name, diff_dict in result_dict_2405.items():
+        print(win_name)
+        for cedian, diff in diff_dict.items():
+            print(cedian, diff)

+ 49 - 0
tmp/extract_dbdata_to_csv.py

@@ -0,0 +1,49 @@
+import pandas as pd
+
+from service.common_connect import trans
+
+wind_farms = {
+    "WOF35900004": "平陆风电场",
+    "WOF35100072": "阳曲风电场",
+    "WOF35100073": "古交风电场",
+    "WOF35200074": "马家梁风电场",
+    "WOF35400075": "太谷风电场",
+    "WOF35900076": "坡底风电场",
+    "WOF35300077": "西潘风电场",
+    "WOF35900078": "芮城风电场",
+    "WOF34900079": "右玉风光互补电站",
+    "WOF35800080": "贺家沟",
+    "WOF35800081": "石楼风电场",
+    "WOF35800082": "盂县风光互补电站"
+}
+
+# types = ['minute', 'second', 'warn', 'fault']
+
+types = ['warn', 'fault']
+
+
+def check_exist_table(table_name):
+    sql = f"select count(1) as count from information_schema.tables where table_name= '{table_name}'"
+    print(sql)
+    data = trans.execute(sql)[0]['count']
+
+    return int(data) > 0
+
+
+file_dir = r'C:\Users\wzl\Desktop\中广核104测点\20250513\data'
+
+def get_data(table_name, name, type):
+    col = 'begin_time'
+    if type in ['minute', 'second']:
+        col = 'time_stamp'
+
+    sql = f"select * from {table_name} where {col} > '2025-05-10 00:00:00'"
+    df = pd.read_sql_query(sql, con=trans.get_engine())
+    df.to_csv(f'{file_dir}\\{name}_{type}.csv', index=False, encoding='utf-8')
+
+
+for wind, name in wind_farms.items():
+    for now_type in types:
+        table_name = f'{wind}_{now_type}'
+        if check_exist_table(table_name):
+            get_data(table_name, name, now_type)

+ 81 - 0
tmp/generate_minute_sql.py

@@ -0,0 +1,81 @@
+import pandas as pd
+from sqlalchemy import create_engine
+
+
+def get_engine():
+    username = 'envision'
+    password = 'envision'
+    host = '172.21.6.37'
+    port = 3306
+    dbname = 'envision'
+    return create_engine(f'mysql+pymysql://{username}:{password}@{host}:{port}/{dbname}')
+
+
+def generate_sql(df: pd.DataFrame, wind_name: str):
+    print(f"开始执行{wind_name}")
+    wind_nos = df['风机号'].unique()
+
+    all_sqls = list()
+
+    begin_time_str = '2025-01-01 00:00:00'
+    end_time_str = '2025-03-01 00:00:00'
+    for wind_no in wind_nos:
+        wind_sqls = []
+        index = 0
+
+        stander_cols = list()
+        stander_cols.append('wind_factory')
+        stander_cols.append('wind_no')
+        stander_cols.append('occur_time')
+
+        wind_df = df[df['风机号'] == wind_no]
+        for wind_factory, table, col, en_name in zip(wind_df['风场'], wind_df['历史采样表名'], wind_df['历史采样域名'],
+                                                     wind_df['en_name']):
+            stander_cols.append(en_name)
+            if index == 0:
+                wind_sqls.append(
+                    f"select * from  (select '{wind_factory}' as wind_factory,{wind_no} as wind_no, occur_time, {col} as {en_name}"
+                    f" from {table} where occur_time >= '{begin_time_str}' and occur_time <'{end_time_str}') a{index}")
+                index = index + 1
+            else:
+                wind_sqls.append(
+                    f"\n inner join  "
+                    f"(select '{wind_factory}' as wind_factory,{wind_no} as wind_no, occur_time, {col} as {en_name}"
+                    f" from {table} where occur_time >= '{begin_time_str}' and occur_time <'{end_time_str}') a{index} "
+                    f"on a{index - 1}.wind_factory = a{index}.wind_factory and a{index - 1}.wind_no = a{index}.wind_no"
+                    f" and a{index - 1}.occur_time = a{index}.occur_time")
+                index = index + 1
+
+        result_sql = "".join(wind_sqls) + ";"
+        stander_cols_str = "'" + "',".join(stander_cols) + "'"
+        all_sqls.append((result_sql, stander_cols_str))
+
+    return all_sqls
+
+
+def show_sqls(stander_cols_str, datas):
+    for index, data in enumerate(datas):
+        print(f'String [] cols = {"".join(stander_cols_str[index])}')
+        print()
+        print(data)
+    print()
+
+
+def save_to_csv(datas, name):
+    dfs = list()
+    for data in datas:
+        dfs.append(pd.read_sql(data, get_engine()))
+
+    df = pd.concat(dfs, ignore_index=True)
+
+    df.to_csv(name + ".csv", encoding='utf8', index=False)
+
+
+if __name__ == '__main__':
+    df = pd.read_csv(r"C:\Users\wzl\Desktop\中广核104测点\min_tables.csv")
+
+    datas = generate_sql(df[df['风场'] == '右玉'], '右玉')
+
+    show_sqls(datas[1], datas[0])
+
+    # save_to_csv(datas[0], '右玉')

+ 59 - 0
tmp/generate_minute_sql_sigle_sql.py

@@ -0,0 +1,59 @@
+import datetime
+
+import pandas as pd
+from sqlalchemy import create_engine
+
+
+def get_engine():
+    username = 'envision'
+    password = 'envision'
+    host = '172.21.6.37'
+    port = 3306
+    dbname = 'envision'
+    return create_engine(f'mysql+pymysql://{username}:{password}@{host}:{port}/{dbname}')
+
+
+def generate_sql(df: pd.DataFrame, wind_name: str):
+    print(f"开始执行{wind_name}")
+    wind_nos = df['风机号'].unique()
+
+    all_sqls = list()
+
+    begin_time_str = '2025-01-01 00:00:00'
+    end_time_str = '2025-03-01 00:00:00'
+    for wind_no in wind_nos:
+
+        wind_df = df[df['风机号'] == wind_no]
+        for wind_factory, table, col, en_name in zip(wind_df['风场'], wind_df['历史采样表名'], wind_df['历史采样域名'],
+                                                     wind_df['en_name']):
+            all_sqls.append((wind_factory,
+                             f"select '{wind_factory}' as wind_factory,{wind_no} as wind_no, occur_time, {col} as {en_name}"
+                             f" from {table} where occur_time >= '{begin_time_str}' and occur_time <'{end_time_str}'"))
+
+    return all_sqls
+
+
+def show_sqls(datas):
+    for index, data in enumerate(datas):
+        print('--', data[0])
+        print(data[1])
+    print()
+
+
+def save_to_csv(datas):
+    dfs = list()
+    for index, data in enumerate(datas):
+        begin = datetime.datetime.now()
+        print('开始', begin)
+
+        dfs.append(pd.read_sql(data[1], get_engine()))
+        df.to_csv(data[0] + str(index) + ".csv", encoding='utf8', index=False)
+        print('结束', datetime.datetime.now(), '耗时:', datetime.datetime.now() - begin)
+
+
+if __name__ == '__main__':
+    df = pd.read_csv(r"C:\Users\wzl\Desktop\中广核104测点\min_tables.csv")
+
+    datas = generate_sql(df[df['风场'] == '右玉'], '右玉')
+
+    show_sqls(datas)

+ 105 - 0
tmp/measurepoint.py

@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+"""
+Spyder 编辑器
+
+这是一个临时脚本文件。
+"""
+import os
+
+import pandas as pd
+
+pd.set_option('chained_assignment', None)
+
+select_cols = ['遥测名称', '遥测别名', '风场', '组件', '风机号', '测点']
+
+origin_col_map = {
+    'wind_turbine_number': '风机编号', 'wind_turbine_name': '风机原始名称', 'time_stamp': '时间戳',
+    'active_power': '有功功率', 'rotor_speed': '风轮转速', 'generator_speed': '发电机转速', 'wind_velocity': '风速',
+    'pitch_angle_blade_1': '桨距角1', 'pitch_angle_blade_2': '桨距角2', 'pitch_angle_blade_3': '桨距角3',
+    'cabin_position': '机舱位置', 'true_wind_direction': '绝对风向', 'yaw_error1': '对风角度',
+    'set_value_of_active_power': '有功功率设定值', 'gearbox_oil_temperature': '齿轮箱油温',
+    'generatordrive_end_bearing_temperature': '发电机驱动端轴承温度',
+    'generatornon_drive_end_bearing_temperature': '发电机非驱动端轴承温度', 'cabin_temperature': '机舱内温度',
+    'twisted_cable_angle': '扭缆角度', 'front_back_vibration_of_the_cabin': '机舱前后振动',
+    'side_to_side_vibration_of_the_cabin': '机舱左右振动', 'actual_torque': '实际力矩', 'given_torque': '给定力矩',
+    'clockwise_yaw_count': '顺时针偏航次数', 'counterclockwise_yaw_count': '逆时针偏航次数', 'unusable': '不可利用',
+    'power_curve_available': '功率曲线可用', 'required_gearbox_speed': '齿轮箱转速',
+    'inverter_speed_master_control': '变频器转速(主控)', 'outside_cabin_temperature': '环境温度',
+    'main_bearing_temperature': '主轴承轴承温度',
+    'gearbox_high_speed_shaft_bearing_temperature': '齿轮箱高速轴轴承温度',
+    'gearboxmedium_speed_shaftbearing_temperature': '齿轮箱中速轴轴承温度',
+    'gearbox_low_speed_shaft_bearing_temperature': '齿轮箱低速轴轴承温度',
+    'generator_winding1_temperature': '发电机绕组1温度', 'generator_winding2_temperature': '发电机绕组2温度',
+    'generator_winding3_temperature': '发电机绕组3温度', 'wind_turbine_status': '风机状态1',
+    'wind_turbine_status2': '风机状态2', 'turbulence_intensity': '湍流强度'
+}
+
+
+def save_df(df, name):
+    df.to_excel(r'C:\Users\wzl\Desktop\中广核104测点\total' + os.sep + str(name) + '.xlsx', columns=select_cols,
+                index=False)
+
+
+def common_measurepoint(df, name):
+    df['风场'] = df['遥测别名'].apply(lambda x: x.split('.')[0])
+    df['组件'] = df['遥测别名'].apply(lambda x: x.split('.')[3])
+    df['风机号'] = df['遥测别名'].apply(lambda x: x.split('.')[2])
+    df['测点'] = df['遥测别名'].apply(lambda x: '.'.join(x.split('.')[4:]))
+    save_df(df, name + '测点')
+    return df
+
+
+if __name__ == '__main__':
+    df = pd.read_csv(r"D:\data\tmp\12CZYC.csv", encoding='gbk')
+
+    df = df[~ df['遥测别名'].str.contains('Farm')]
+    df = df[~ df['遥测别名'].str.contains('Statistics')]
+
+    # 添加右玉处理
+    name = '右玉'
+    youyu_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加平陆处理
+    name = '平陆'
+    pinglu_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加芮城处理
+    name = '芮城'
+    ruicheng_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加盂县处理
+    name = '盂县'
+    yuxian_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加古交处理
+    name = '古交'
+    gujiao_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加石楼处理
+    name = '石楼'
+    shilou_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加阳曲处理
+    name = '阳曲'
+    yangqu_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加西潘处理
+    name = '西潘'
+    xipan_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加马家梁处理
+    name = '马家梁'
+    majialiang_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加富风处理
+    name = '富风'
+    fufeng_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加坡底处理
+    name = '坡底'
+    podi_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+
+    # 添加贺家沟处理
+    name = '贺家沟'
+    hejiagou_df = common_measurepoint(df[df['遥测名称'].str.contains(name)], name)
+    # result_df = pd.concat([youyu_df, pinglu_df, ruicheng_df, yuxian_df, gujiao_df, shilou_df])

+ 380 - 0
tmp/measurepoint2404.py

@@ -0,0 +1,380 @@
+# -*- coding: utf-8 -*-
+"""
+Spyder 编辑器
+
+这是一个临时脚本文件。
+"""
+import os
+
+import pandas as pd
+
+pd.set_option('chained_assignment', None)
+
+select_cols = ['遥测ID号', '风场', '风场几期', '风机号', '测点', '标准化中文', '转发顺序号', 'en_name']
+
+origin_col_map = {
+    'wind_turbine_number': '风机编号', 'wind_turbine_name': '风机原始名称', 'time_stamp': '时间戳',
+    'active_power': '有功功率', 'rotor_speed': '风轮转速', 'generator_speed': '发电机转速', 'wind_velocity': '风速',
+    'pitch_angle_blade_1': '桨距角1', 'pitch_angle_blade_2': '桨距角2', 'pitch_angle_blade_3': '桨距角3',
+    'cabin_position': '机舱位置', 'true_wind_direction': '绝对风向', 'yaw_error1': '对风角度',
+    'set_value_of_active_power': '有功功率设定值', 'gearbox_oil_temperature': '齿轮箱油温',
+    'generatordrive_end_bearing_temperature': '发电机驱动端轴承温度',
+    'generatornon_drive_end_bearing_temperature': '发电机非驱动端轴承温度', 'cabin_temperature': '机舱内温度',
+    'twisted_cable_angle': '扭缆角度', 'front_back_vibration_of_the_cabin': '机舱前后振动',
+    'side_to_side_vibration_of_the_cabin': '机舱左右振动', 'actual_torque': '实际力矩', 'given_torque': '给定力矩',
+    'clockwise_yaw_count': '顺时针偏航次数', 'counterclockwise_yaw_count': '逆时针偏航次数', 'unusable': '不可利用',
+    'power_curve_available': '功率曲线可用', 'required_gearbox_speed': '齿轮箱转速',
+    'inverter_speed_master_control': '变频器转速(主控)', 'outside_cabin_temperature': '环境温度',
+    'main_bearing_temperature': '主轴承轴承温度',
+    'gearbox_high_speed_shaft_bearing_temperature': '齿轮箱高速轴轴承温度',
+    'gearboxmedium_speed_shaftbearing_temperature': '齿轮箱中速轴轴承温度',
+    'gearbox_low_speed_shaft_bearing_temperature': '齿轮箱低速轴轴承温度',
+    'generator_winding1_temperature': '发电机绕组1温度', 'generator_winding2_temperature': '发电机绕组2温度',
+    'generator_winding3_temperature': '发电机绕组3温度', 'wind_turbine_status': '风机状态1',
+    'wind_turbine_status2': '风机状态2', 'turbulence_intensity': '湍流强度'
+}
+
+
+def youyu_measurepoint(df, name):
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[0][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:len(name)])
+
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[1][0:3])
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('_')[1].split('-')[1][3:])
+    show_measurepoint(df, name + '测点')
+    col_mapping = {
+        "3#桨叶片角度": "pitch_angle_blade_3",
+        "机舱侧向振动(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "机舱轴向振动(已滤波)": "front_back_vibration_of_the_cabin",
+        "机舱角度": "cabin_position",
+        "扭缆角度": "twisted_cable_angle",
+        "发电机有功功率": "active_power",
+        "发电机驱动端轴承温度": "generatordrive_end_bearing_temperature",
+        "发电机非驱动端轴承温度": "generatornon_drive_end_bearing_temperature",
+        "发电机定子U相线圈温度": "generator_winding1_temperature",
+        "发电机定子V相线圈温度": "generator_winding2_temperature",
+        "发电机定子W相线圈温度": "generator_winding3_temperature",
+        "绕组温度1": "generator_winding1_temperature",
+        "绕组温度2": "generator_winding2_temperature",
+        "绕组温度3": "generator_winding3_temperature",
+        "舱内温度": "cabin_temperature",
+        "舱外温度": "outside_cabin_temperature",
+        "风向": "true_wind_direction",
+        "风速": "wind_velocity",
+        "机舱中轴线与风向夹角": "yaw_error1",
+        "1#桨叶片角度": "pitch_angle_blade_1",
+        "2#桨叶片角度": "pitch_angle_blade_2",
+        "发电机转速": "generator_speed",
+        "主轴转速": "rotor_speed",
+        "齿轮箱高速轴非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",
+        "齿轮箱油池温度": "gearbox_oil_temperature",
+        "齿轮箱中速轴非驱动端轴承温度": "gearboxmedium_speed_shaftbearing_temperature",
+        "主轴承外圈温度": "main_bearing_temperature",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, name + '测点')
+    return df
+
+
+def pinglu_measurepoint(df, name):
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[0])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:len(name)])
+
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[2].split('-')[1][0:2])
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('_')[1].split('-')[1][2:])
+    show_measurepoint(df, name + '测点')
+    col_mapping = {
+        "发电机非驱动端轴承温度": "generatornon_drive_end_bearing_temperature",
+        "发电机定子U相线圈温度": "generator_winding1_temperature",
+        "发电机定子V相线圈温度": "generator_winding2_temperature",
+        "发电机转速": "generator_speed",
+        "发电机驱动端轴承温度": "generatordrive_end_bearing_temperature",
+        "2#桨叶片角度": "pitch_angle_blade_2",
+        "主轴承外圈温度": "main_bearing_temperature",
+        "发电机定子W相线圈温度": "generator_winding3_temperature",
+        "发电机有功功率": "active_power",
+        "主轴转速": "rotor_speed",
+        "齿轮箱高速轴非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",
+        "1#桨叶片角度": "pitch_angle_blade_1",
+        "舱外温度": "outside_cabin_temperature",
+        "舱内温度": "cabin_temperature",
+        "风向": "true_wind_direction",
+        "机舱中轴线与风向夹角": "yaw_error1",
+        "机舱角度": "cabin_position",
+        "扭缆角度": "twisted_cable_angle",
+        "3#桨叶片角度": "pitch_angle_blade_3",
+        "机舱轴向振动(已滤波)": "front_back_vibration_of_the_cabin",
+        "风速": "wind_velocity",
+        "机舱侧向振动(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "齿轮箱高速轴费非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",  # 与“齿轮箱高速轴非驱动端轴承温度”相同
+        "机舱角度(位置)": "cabin_position",
+        "机舱侧向振动值(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "机舱轴向振动值(已滤波)": "front_back_vibration_of_the_cabin",
+        "机舱与风向夹角": "yaw_error1",
+        "1#桨叶片角度(桨距角)": "pitch_angle_blade_1",
+        "2#桨叶片角度(桨距角)": "pitch_angle_blade_2",
+        "3#桨叶片角度(桨距角)": "pitch_angle_blade_3",
+        "齿轮箱高速轴驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",  # 根据规则,齿轮箱高速轴不区分驱动端和非驱动端
+        "齿轮箱中间轴非驱动端轴承温度": "gearboxmedium_speed_shaftbearing_temperature",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, name + '测点')
+    return df
+
+
+def ruicheng_measurepoint(df, name):
+    # 根据芮城数据格式调整字段提取逻辑
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:len(name)])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1][6:9])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('_')[1].split('-')[1][3:])
+    show_measurepoint(df, name + '测点')
+    col_mapping = {
+        "1#桨叶片角度": "pitch_angle_blade_1",
+        "2#桨叶片角度": "pitch_angle_blade_2",
+        "3#桨叶片角度": "pitch_angle_blade_3",
+        "舱内温度": "cabin_temperature",
+        "舱外温度": "outside_cabin_temperature",
+        "齿轮箱高速轴非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",
+        "齿轮箱油池温度": "gearbox_oil_temperature",
+        "发电机定子U相线圈温度": "generator_winding1_temperature",
+        "发电机定子V相线圈温度": "generator_winding2_temperature",
+        "发电机定子W相线圈温度": "generator_winding3_temperature",
+        "发电机非驱动端轴承温度": "generatornon_drive_end_bearing_temperature",
+        "发电机驱动端轴承温度": "generatordrive_end_bearing_temperature",
+        "发电机有功功率": "active_power",
+        "发电机转速": "generator_speed",
+        "风速": "wind_velocity",
+        "风向": "true_wind_direction",
+        "机舱侧向振动(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "机舱角度": "cabin_position",
+        "机舱中轴线与风向夹角": "yaw_error1",
+        "机舱轴向振动(已滤波)": "front_back_vibration_of_the_cabin",
+        "扭缆角度": "twisted_cable_angle",
+        "主轴承外圈温度": "main_bearing_temperature",
+        "主轴转速": "rotor_speed",
+        "机舱与风向夹角": "yaw_error1",
+        "机舱角度(位置)": "cabin_position",
+        "1#桨叶片角度(桨距角)": "pitch_angle_blade_1",
+        "2#桨叶片角度(桨距角)": "pitch_angle_blade_2",
+        "3#桨叶片角度(桨距角)": "pitch_angle_blade_3",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, name + '测点')
+    return df
+
+
+def yuxian_measurepoint(df, name):
+    # 根据孟县数据格式调整字段提取逻辑
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[0][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:len(name)])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('-')[1][0:3])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('-')[1][3:])
+
+    show_measurepoint(df, name + '测点')
+    col_mapping = {
+        "发电机定子W相线圈温度": "generator_winding3_temperature",
+        "发电机非驱动端轴承温度": "generatornon_drive_end_bearing_temperature",
+        "机舱侧向振动(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "风速": "wind_velocity",
+        "机舱中轴线与风向夹角": "yaw_error1",
+        "1#桨叶片角度": "pitch_angle_blade_1",
+        "2#桨叶片角度": "pitch_angle_blade_2",
+        "发电机有功功率": "active_power",
+        "发电机转速": "generator_speed",
+        "风向": "true_wind_direction",
+        "发电机驱动端轴承温度": "generatordrive_end_bearing_temperature",
+        "机舱轴向振动(已滤波)": "front_back_vibration_of_the_cabin",
+        "机舱角度": "cabin_position",
+        "扭揽角度": "twisted_cable_angle",
+        "发电机定子U相线圈温度": "generator_winding1_temperature",
+        "发电机定子V相线圈温度": "generator_winding2_temperature",
+        "主轴转速": "rotor_speed",
+        "齿轮箱中速轴非驱动端轴承温度": "gearboxmedium_speed_shaftbearing_temperature",
+        "齿轮箱高速轴非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",
+        "齿轮箱油池温度": "gearbox_oil_temperature",
+        "主轴承外圈温度": "main_bearing_temperature",
+        "舱内温度": "cabin_temperature",
+        "舱外温度": "outside_cabin_temperature",
+        "3#桨叶片角度": "pitch_angle_blade_3",
+        "扭缆角度": "twisted_cable_angle",
+        "齿轮箱中间轴非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",  # 与“齿轮箱中速轴非驱动端轴承温度”相同
+        "主轴(风轮)转速": "rotor_speed",
+        "1#桨叶片角度(桨距角)": "pitch_angle_blade_1",
+        "2#桨叶片角度(桨距角)": "pitch_angle_blade_2",
+        "3#桨叶片角度(桨距角)": "pitch_angle_blade_3",
+        "机舱角度(位置)": "cabin_position",
+        "机舱侧向振动值(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "机舱轴向振动值(已滤波)": "front_back_vibration_of_the_cabin",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, name + '测点')
+    return df
+
+
+def gujiao_measurepoint(df, name):
+    # 古交数据格式处理
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[0][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:len(name)])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('-')[1][0:3])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('-')[1][3:])
+
+    show_measurepoint(df, name + '测点')
+    col_mapping = {
+        "机舱与风向夹角": "yaw_error1",
+        "1#桨叶片角度(桨距角)": "pitch_angle_blade_1",
+        "2#桨叶片角度(桨距角)": "pitch_angle_blade_2",
+        "3#桨叶片角度(桨距角)": "pitch_angle_blade_3",
+        "主轴转速": "rotor_speed",
+        "齿轮箱高速轴非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",
+        "齿轮箱油池温度": "gearbox_oil_temperature",
+        "主轴承外圈温度": "main_bearing_temperature",
+        "发电机转速": "generator_speed",
+        "发电机驱动端轴承温度": "generatordrive_end_bearing_temperature",
+        "发电机非驱动端轴承温度": "generatornon_drive_end_bearing_temperature",
+        "发电机定子U相线圈温度": "generator_winding1_temperature",
+        "发电机定子V相线圈温度": "generator_winding2_temperature",
+        "发电机定子W相线圈温度": "generator_winding3_temperature",
+        "舱内温度": "cabin_temperature",
+        "舱外温度": "outside_cabin_temperature",
+        "风向": "true_wind_direction",
+        "机舱角度(位置)": "cabin_position",
+        "偏航角度(扭缆角度)": "twisted_cable_angle",
+        # "桨叶片角度(桨距角)": ["pitch_angle_blade_1", "pitch_angle_blade_2", "pitch_angle_blade_3"],  # 根据具体桨叶选择
+        "机舱侧向振动值(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "机舱轴向振动值(已滤波)": "front_back_vibration_of_the_cabin",
+        "风速": "wind_velocity",
+        "发电机有功功率": "active_power",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, name + '测点')
+    return df
+
+
+def shilou_measurepoint(df, name):
+    # 石楼数据格式处理
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[0][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:len(name)])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('-')[1][0:3])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('-')[1][3:])
+    show_measurepoint(df, name + '测点')
+    col_mapping = {
+        "舱内温度": "cabin_temperature",
+        "舱外温度": "outside_cabin_temperature",
+        "偏航角度(扭缆角度)": "twisted_cable_angle",
+        "风向": "true_wind_direction",
+        "风速": "wind_velocity",
+        "机舱中轴线与风向夹角": "yaw_error1",
+        "1#桨叶片角度": "pitch_angle_blade_1",
+        "2#桨叶片角度": "pitch_angle_blade_2",
+        "3#桨叶片角度": "pitch_angle_blade_3",
+        "主轴转速": "rotor_speed",
+        "机舱轴向振动(已滤波)": "front_back_vibration_of_the_cabin",
+        "发电机有功功率": "active_power",
+        "发电机转速": "generator_speed",
+        "机舱与风向夹角": "yaw_error1",
+        "1#桨叶片角度(桨距角)": "pitch_angle_blade_1",
+        "2#桨叶片角度(桨距角)": "pitch_angle_blade_2",
+        "3#桨叶片角度(桨距角)": "pitch_angle_blade_3",
+        "齿轮箱油池温度": "gearbox_oil_temperature",
+        "主轴后轴承温度": "main_bearing_temperature",  # 根据规则,主轴后轴承温度对应 main_bearing_temperature
+        "发电机驱动端轴承温度": "generatordrive_end_bearing_temperature",
+        "发电机非驱动端轴承温度": "generatornon_drive_end_bearing_temperature",
+        "齿轮箱高速轴非驱动端轴承温度": "gearbox_high_speed_shaft_bearing_temperature",
+        "发电机定子U相线圈温度": "generator_winding1_temperature",
+        "发电机定子V相线圈温度": "generator_winding2_temperature",
+        "发电机定子W相线圈温度": "generator_winding3_temperature",
+        "机舱侧向振动值(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "机舱轴向振动值(已滤波)": "front_back_vibration_of_the_cabin",
+        "齿轮箱中速轴非驱动端轴承温度": "gearboxmedium_speed_shaftbearing_temperature",
+        "机舱角度(位置)": "cabin_position",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, name + '测点')
+    return df
+
+
+def show_measurepoint(df, name):
+    print(f'--------{name}-----------')
+    for cn_name in df['测点'].unique():
+        print(f"{cn_name}:'',")
+    print('-------------------')
+
+
+def save_df(df, name):
+    df['遥测ID号'] = df['遥测ID号'].apply(lambda x: x.replace('遥测定义表 ', '').replace('遥测值', '').strip())
+    df['标准化中文'] = df['en_name'].map(origin_col_map)
+
+    df.to_csv(r'C:\Users\wzl\Desktop\中广核104测点\2404' + os.sep + str(name) + '.csv',
+              columns=select_cols,
+              index=False, encoding='utf8')
+
+
+if __name__ == '__main__':
+    df = pd.read_csv(r"D:\data\tmp\2404ZF.csv", encoding='gbk')
+
+    # 添加右玉处理
+    youyu_df = youyu_measurepoint(df[df['遥测ID号'].str.contains('右玉')], '右玉')
+
+    # 添加平陆处理
+    pinglu_df = pinglu_measurepoint(df[df['遥测ID号'].str.contains('平陆')], '平陆')
+
+    # 添加芮城处理
+    ruicheng_df = ruicheng_measurepoint(df[df['遥测ID号'].str.contains('芮城')], '芮城')
+
+    # 添加盂县处理
+    yuxian_df = yuxian_measurepoint(df[df['遥测ID号'].str.contains('盂县')], '盂县')
+
+    # 添加古交处理
+    gujiao_df = gujiao_measurepoint(df[df['遥测ID号'].str.contains('古交')], '古交')
+
+    # 添加石楼处理
+    shilou_df = shilou_measurepoint(df[df['遥测ID号'].str.contains('石楼')], '石楼')
+
+    result_df = pd.concat([youyu_df, pinglu_df, ruicheng_df, yuxian_df, gujiao_df, shilou_df])
+
+    save_df(result_df, '2404测点')

+ 351 - 0
tmp/measurepoint2405.py

@@ -0,0 +1,351 @@
+# -*- coding: utf-8 -*-
+"""
+Spyder 编辑器
+
+这是一个临时脚本文件。
+"""
+import os
+
+import pandas as pd
+
+pd.set_option('chained_assignment', None)
+
+select_cols = ['遥测ID号', '风场', '风场几期', '风机号', '测点', '标准化中文', '转发顺序号', 'en_name']
+
+origin_col_map = {
+    'wind_turbine_number': '风机编号', 'wind_turbine_name': '风机原始名称', 'time_stamp': '时间戳',
+    'active_power': '有功功率', 'rotor_speed': '风轮转速', 'generator_speed': '发电机转速', 'wind_velocity': '风速',
+    'pitch_angle_blade_1': '桨距角1', 'pitch_angle_blade_2': '桨距角2', 'pitch_angle_blade_3': '桨距角3',
+    'cabin_position': '机舱位置', 'true_wind_direction': '绝对风向', 'yaw_error1': '对风角度',
+    'set_value_of_active_power': '有功功率设定值', 'gearbox_oil_temperature': '齿轮箱油温',
+    'generatordrive_end_bearing_temperature': '发电机驱动端轴承温度',
+    'generatornon_drive_end_bearing_temperature': '发电机非驱动端轴承温度', 'cabin_temperature': '机舱内温度',
+    'twisted_cable_angle': '扭缆角度', 'front_back_vibration_of_the_cabin': '机舱前后振动',
+    'side_to_side_vibration_of_the_cabin': '机舱左右振动', 'actual_torque': '实际力矩', 'given_torque': '给定力矩',
+    'clockwise_yaw_count': '顺时针偏航次数', 'counterclockwise_yaw_count': '逆时针偏航次数', 'unusable': '不可利用',
+    'power_curve_available': '功率曲线可用', 'required_gearbox_speed': '齿轮箱转速',
+    'inverter_speed_master_control': '变频器转速(主控)', 'outside_cabin_temperature': '环境温度',
+    'main_bearing_temperature': '主轴承轴承温度',
+    'gearbox_high_speed_shaft_bearing_temperature': '齿轮箱高速轴轴承温度',
+    'gearboxmedium_speed_shaftbearing_temperature': '齿轮箱中速轴轴承温度',
+    'gearbox_low_speed_shaft_bearing_temperature': '齿轮箱低速轴轴承温度',
+    'generator_winding1_temperature': '发电机绕组1温度', 'generator_winding2_temperature': '发电机绕组2温度',
+    'generator_winding3_temperature': '发电机绕组3温度', 'wind_turbine_status': '风机状态1',
+    'wind_turbine_status2': '风机状态2', 'turbulence_intensity': '湍流强度'
+}
+
+table_exists_cols = ['wind_turbine_number', 'wind_turbine_name', 'time_stamp', 'active_power', 'rotor_speed',
+                     'generator_speed', 'wind_velocity', 'pitch_angle_blade_1', 'pitch_angle_blade_2',
+                     'pitch_angle_blade_3', 'cabin_position', 'true_wind_direction', 'yaw_error1',
+                     'set_value_of_active_power', 'gearbox_oil_temperature', 'generatordrive_end_bearing_temperature',
+                     'generatornon_drive_end_bearing_temperature', 'cabin_temperature', 'twisted_cable_angle',
+                     'front_back_vibration_of_the_cabin', 'side_to_side_vibration_of_the_cabin', 'actual_torque',
+                     'given_torque', 'clockwise_yaw_count', 'counterclockwise_yaw_count', 'unusable',
+                     'power_curve_available', 'required_gearbox_speed', 'inverter_speed_master_control',
+                     'outside_cabin_temperature', 'main_bearing_temperature',
+                     'gearbox_high_speed_shaft_bearing_temperature', 'gearboxmedium_speed_shaftbearing_temperature',
+                     'gearbox_low_speed_shaft_bearing_temperature', 'generator_winding1_temperature',
+                     'generator_winding2_temperature', 'generator_winding3_temperature', 'wind_turbine_status',
+                     'wind_turbine_status2', 'turbulence_intensi']
+
+
+def yangqu_measurepoint(df):
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[0][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:2])
+
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1].split('-')[1][0:3])
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('_')[1].split('-')[1][3:])
+    show_measurepoint(df, '阳曲测点')
+    col_mapping = {
+        "机舱中轴线与风向夹角": "yaw_error1",
+        "风向": "true_wind_direction",
+        "舱外温度": "outside_cabin_temperature",
+        "扭揽角度": "twisted_cable_angle",
+        "1#桨叶片角度": "pitch_angle_blade_1",
+        "2#桨叶片角度": "pitch_angle_blade_2",
+        "3#桨叶片角度": "pitch_angle_blade_3",
+        "发电机转速": "generator_speed",
+        "发电机有功功率": "active_power",
+        "机舱侧向振动(已滤波)": "side_to_side_vibration_of_the_cabin",
+        "机舱轴向振动(已滤波)": "front_back_vibration_of_the_cabin",
+        "舱内温度": "cabin_temperature",
+        "风速": "wind_velocity",
+        "发电机前轴承温度1": "generatordrive_end_bearing_temperature",  # 根据规则,发电机前轴承对应驱动端轴承
+        "发电机后轴承温度1": "generatornon_drive_end_bearing_temperature",  # 根据规则,发电机后轴承对应非驱动端轴承
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, '阳曲测点')
+
+    return df
+
+
+def xipan_measurepoint(df):
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:2])
+
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1][6:])
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[2]))
+    show_measurepoint(df, '西潘测点')
+    col_mapping = {
+        "风速": "wind_velocity",
+        "机舱与风向夹角": "yaw_error1",
+        "风向": "true_wind_direction",
+        "舱外温度": "outside_cabin_temperature",
+        "偏航角度(扭缆角度)": "twisted_cable_angle",
+        "1#桨叶片角度(桨距角)": "pitch_angle_blade_1",
+        "2#桨叶片角度(桨距角)": "pitch_angle_blade_2",
+        "3#桨叶片角度(桨距角)": "pitch_angle_blade_3",
+        "发电机有功功率": "active_power",
+        "舱内温度": "cabin_temperature",
+        "发电机转速": "generator_speed",
+        "桨叶1位置给定": "pitch_angle_blade_1",  # 假设为桨叶1的位置给定值
+        "桨叶2位置给定": "pitch_angle_blade_2",  # 假设为桨叶2的位置给定值
+        "桨叶3位置给定": "pitch_angle_blade_3",  # 假设为桨叶3的位置给定值
+        "机舱位置": "cabin_position",
+        "齿轮箱油温": "gearbox_oil_temperature",
+        "发电机定子L1绕组温度": "generator_winding1_temperature",  # 假设L1对应U相
+        "发电机定子L2绕组温度": "generator_winding2_temperature",  # 假设L2对应V相
+        "发电机定子L3绕组温度": "generator_winding3_temperature",  # 假设L3对应W相
+        "发电机驱动端轴承温度": "generatordrive_end_bearing_temperature",
+        "发电机非驱动端轴承温度": "generatornon_drive_end_bearing_temperature",
+        "电网有功功率": "active_power",  # 假设为电网有功功率
+        "实时风速": "wind_velocity",  # 假设为实时风速
+        "3s风向(0-360度)": "true_wind_direction",  # 假设为3秒平均风向
+        "主轴温度": "main_bearing_temperature",  # 假设为主轴温度
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, '西潘测点')
+    return df
+
+
+def majialiang_measurepoint(df, name):
+    # 根据马家梁数据格式调整字段提取逻辑
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1][0:5])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:len(name)])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('-')[1][0:3])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[1:]).split('_')[1].split('-')[1][3:])
+    show_measurepoint(df, name + '测点')
+
+    col_mapping = {
+        "风速": "wind_velocity",
+        "机舱与风向夹角": "yaw_error1",
+        "风向": "true_wind_direction",
+        "偏航角度(扭缆角度)": "twisted_cable_angle",
+        "1#桨叶片角度(桨距角)": "pitch_angle_blade_1",
+        "2#桨叶片角度(桨距角)": "pitch_angle_blade_2",
+        "3#桨叶片角度(桨距角)": "pitch_angle_blade_3",
+        "发电机有功功率": "active_power",
+        "发电机前轴承温度1": "generatordrive_end_bearing_temperature",  # 前轴承对应驱动端
+        "发电机后轴承温度1": "generatornon_drive_end_bearing_temperature",  # 后轴承对应非驱动端
+        "有功功率": "active_power",  # 与“发电机有功功率”相同
+        "瞬时风速": "wind_velocity",  # 假设为瞬时风速
+        "风向角": "yaw_error1",  # 与“风向”相同
+        "桨距角1": "pitch_angle_blade_1",  # 与“1#桨叶片角度(桨距角)”相同
+        "桨距角2": "pitch_angle_blade_2",  # 与“2#桨叶片角度(桨距角)”相同
+        "桨距角3": "pitch_angle_blade_3",  # 与“3#桨叶片角度(桨距角)”相同
+        "发电机转速": "generator_speed",
+        "发电机定子U温度": "generator_winding1_temperature",  # U相温度
+        "发电机定子V温度": "generator_winding2_temperature",  # V相温度
+        "发电机定子W温度": "generator_winding3_temperature",  # W相温度
+        "驱动端轴承温度": "generatordrive_end_bearing_temperature",  # 与“发电机前轴承温度1”相同
+        "高速轴承温度": "gearbox_high_speed_shaft_bearing_temperature",  # 假设为齿轮箱高速轴轴承温度
+        "舱外温度": "outside_cabin_temperature",
+        "舱内温度": "cabin_temperature",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, name + '测点')
+    return df
+
+
+def fufeng_measurepoint(df):
+    # 根据孟县数据格式调整字段提取逻辑
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[0])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:2])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('-')[1])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[2:]))
+
+    show_measurepoint(df, '富风测点')
+    col_mapping = {
+        "机组有功功率": "active_power",
+        "机组1#叶片变桨角度": "pitch_angle_blade_1",
+        "机组2#叶片变桨角度": "pitch_angle_blade_2",
+        "机组3#叶片变桨角度": "pitch_angle_blade_3",
+        "机组主轴前轴承温度": "main_bearing_temperature",  # 假设为主轴前轴承温度
+        "机组齿轮箱油池温度": "gearbox_oil_temperature",
+        "机组发电机转速": "generator_speed",
+        "机组发电机绕组u1温度": "generator_winding1_temperature",  # 假设u1对应U相
+        "机组发电机绕组v1温度": "generator_winding2_temperature",  # 假设v1对应V相
+        "机组发电机绕组w1温度": "generator_winding3_temperature",  # 假设w1对应W相
+        "机组发电机前轴承温度": "generatordrive_end_bearing_temperature",  # 前轴承对应驱动端
+        "机组发电机后轴承温度": "generatornon_drive_end_bearing_temperature",  # 后轴承对应非驱动端
+        "机组瞬时风速": "wind_velocity",  # 假设为瞬时风速
+        "机组瞬时风向": "true_wind_direction",  # 假设为瞬时风向
+        "机组环境温度": "outside_cabin_temperature",  # 假设环境温度为舱外温度
+        "机组机舱温度": "cabin_temperature",
+        "机组机舱X方向振动": "side_to_side_vibration_of_the_cabin",  # 假设X方向为侧向振动
+        "机组机舱Y方向振动": "front_back_vibration_of_the_cabin",  # 假设Y方向为轴向振动
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, '富风测点')
+    return df
+
+
+def podi_measurepoint(df):
+    # 坡底数据格式处理
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1][0:4])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:2])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('-')[1][0:2])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[2:]))
+
+    show_measurepoint(df, '坡底测点')
+
+    col_mapping = {
+        "主轴转速": "rotor_speed",
+        "发电机转速": "generator_speed",
+        "风向": "true_wind_direction",
+        "风速": "wind_velocity",
+        "机舱温度": "cabin_temperature",
+        "室外温度": "outside_cabin_temperature",
+        "主轴轴承温度": "main_bearing_temperature",  # 假设主轴轴承温度对应主轴承温度
+        "齿轮箱高速轴承端温度": "gearbox_high_speed_shaft_bearing_temperature",  # 假设为齿轮箱高速轴轴承温度
+        "发电机驱动端温度": "generatordrive_end_bearing_temperature",  # 驱动端轴承温度
+        "发电机非驱动端温度": "generatornon_drive_end_bearing_temperature",  # 非驱动端轴承温度
+        "扭缆角度": "twisted_cable_angle",
+        "轴1桨叶实际角度": "pitch_angle_blade_1",  # 假设轴1对应1#桨叶
+        "轴2桨叶实际角度": "pitch_angle_blade_2",  # 假设轴2对应2#桨叶
+        "轴3桨叶实际角度": "pitch_angle_blade_3",  # 假设轴3对应3#桨叶
+        "机舱Y方向振动值": "front_back_vibration_of_the_cabin",  # 假设Y方向为轴向振动
+        "机舱X方向振动值": "side_to_side_vibration_of_the_cabin",  # 假设X方向为侧向振动
+        "有功功率": "active_power",
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, '坡底测点')
+    return df
+
+
+def hejiagou_measurepoint(df):
+    # 贺家沟数据格式处理
+    df['风场几期'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('_')[1][0:5])
+    df['风场'] = df['风场几期'].apply(lambda x: x[0:3])
+
+    # 假设风机号在第三个分割段中
+    df['风机号'] = df['遥测ID号'].apply(lambda x: x.split(' ')[1].split('-')[1])
+    # 测点提取可能需要调整切片位置
+    df['测点'] = df['遥测ID号'].apply(
+        lambda x: ''.join(x.replace('遥测值', '').strip().split(' ')[2]))
+    show_measurepoint(df, '贺家沟测点')
+    col_mapping = {
+        "环境温度": "outside_cabin_temperature",  # 假设环境温度为舱外温度
+        "风速1s": "wind_velocity",  # 假设为1秒平均风速
+        "绝对风向": "true_wind_direction",  # 假设为绝对风向
+        "桨角1": "pitch_angle_blade_1",  # 1#桨叶角度
+        "桨角2": "pitch_angle_blade_2",  # 2#桨叶角度
+        "桨角3": "pitch_angle_blade_3",  # 3#桨叶角度
+        "发电机转速": "generator_speed",
+        # "齿轮箱转速": "generator_speed",  # 假设为齿轮箱转速
+        "发电机U相温度": "generator_winding1_temperature",  # U相温度
+        "发电机V相温度": "generator_winding2_temperature",  # V相温度
+        "发电机W相温度": "generator_winding3_temperature",  # W相温度
+        "发电机轴承温度": "generatordrive_end_bearing_temperature",  # 假设为发电机轴承温度(未区分驱动端和非驱动端)
+        "齿轮箱高速轴前轴承温度": "gearbox_high_speed_shaft_bearing_temperature",  # 假设为齿轮箱高速轴前轴承温度
+        "机舱内温度": "cabin_temperature",
+        "变流器有功功率": "active_power",  # 假设为变流器有功功率
+        "塔筒左右振动": "side_to_side_vibration_of_the_cabin",  # 假设为塔筒左右振动
+        "塔筒前后振动": "front_back_vibration_of_the_cabin",  # 假设为塔筒前后振动
+    }
+
+    df['en_name'] = df['测点'].map(col_mapping)
+    print(df.groupby('en_name').count())
+
+    df.sort_values(by='转发顺序号', inplace=True)
+    save_df(df, '贺家沟测点')
+    return df
+
+
+def not_in_exists_col(df):
+    print("jinrule")
+    tuple_datas = set()
+    for feichang, fengji, cedian, col in zip(df['风场'], df['风机号'], df['测点'], df['en_name']):
+        if col not in table_exists_cols:
+            tuple_datas.add((feichang, cedian, col))
+            # print(feichang, cedian, col)
+
+    for col in tuple_datas:
+        print(col)
+    print('-----------------')
+
+
+def show_measurepoint(df, name):
+    print(f'--------{name}-----------')
+    for cn_name in df['测点'].unique():
+        print(f"{cn_name}:'',")
+    print('-------------------')
+
+
+def save_df(df, name):
+    df['遥测ID号'] = df['遥测ID号'].apply(lambda x: x.replace('遥测定义表 ', '').replace('遥测值', '').strip())
+
+    df['标准化中文'] = df['en_name'].map(origin_col_map)
+
+    df.to_csv(r'C:\Users\wzl\Desktop\中广核104测点\2405' + os.sep + str(name) + '.csv',
+              columns=select_cols,
+              index=False, encoding='utf8')
+
+
+if __name__ == '__main__':
+    # df = pd.read_csv(r"D:\data\tmp\2405ZF.csv", encoding='gbk')
+
+    df = pd.read_csv(r"D:\data\tmp\2405ZF.csv", encoding='utf8')
+
+    # 添加阳曲处理
+    yangqu_df = yangqu_measurepoint(df[df['遥测ID号'].str.contains('阳曲')])
+
+    # 添加西潘处理
+    xipan_df = xipan_measurepoint(df[df['遥测ID号'].str.contains('西潘')])
+
+    # 添加马家梁处理
+    majialiang_df = majialiang_measurepoint(df[df['遥测ID号'].str.contains('马家梁')], '马家梁')
+
+    # 添加富风处理
+    fufeng_df = fufeng_measurepoint(df[df['遥测ID号'].str.contains('富风')])
+
+    # 添加坡底处理
+    podi_df = podi_measurepoint(df[df['遥测ID号'].str.contains('坡底')])
+
+    # 添加贺家沟处理
+    hejiagou_df = hejiagou_measurepoint(df[df['遥测ID号'].str.contains('贺家沟')])
+
+    result_df = pd.concat([yangqu_df, xipan_df, majialiang_df, fufeng_df, podi_df, hejiagou_df])
+    not_in_exists_col(result_df)
+
+    save_df(result_df, '2405测点')

+ 27 - 0
tmp/min_max_nunm.py

@@ -0,0 +1,27 @@
+import json
+
+if __name__ == '__main__':
+
+    file_path = r'C:\Users\wzl\Desktop\241\2404 (复件)\20250310.txt'
+
+    result_dict = dict()
+    res_min = 9999999
+    res_max = -1
+    with open(file_path, 'r') as f:
+        line = f.readline()
+        while line:
+            fixed_str = line.replace('{', '{"').replace(':"', '":"').replace(',', ',"')
+            line_data = {}
+            line_data = json.loads(fixed_str)
+            del line_data['-1']
+            now_min = min([int(i) for i in line_data.keys()])
+            if now_min < res_min:
+                res_min = now_min
+
+            now_max = max([int(i) for i in line_data.keys()])
+            if now_max > res_max:
+                res_max = now_max
+
+            line = f.readline()
+
+    print(res_min, res_max)

+ 21 - 0
tmp/qingli_04月数据.py

@@ -0,0 +1,21 @@
+wind_farms = {
+    "WOF35900004": "平陆风电场",
+    "WOF35100072": "阳曲风电场",
+    "WOF35100073": "古交风电场",
+    "WOF35200074": "马家梁风电场",
+    "WOF35400075": "太谷风电场",
+    "WOF35900076": "坡底风电场",
+    "WOF35300077": "西潘风电场",
+    "WOF35900078": "芮城风电场",
+    "WOF34900079": "右玉风光互补电站",
+    "WOF35800080": "贺家沟",
+    "WOF35800081": "石楼风电场",
+    "WOF35800082": "盂县风光互补电站"
+}
+
+types = ['warn', 'fault', 'minute', 'second']
+
+for code, name in wind_farms.items():
+    for type in types:
+        sql = f'alter table {code}_{type} TRUNCATE PARTITION p202504'
+        print(sql)

+ 96 - 0
tmp/receiver104.py

@@ -0,0 +1,96 @@
+from c104 import Client
+import time
+import logging
+
+# 配置日志
+logging.basicConfig(
+    level=logging.INFO,
+    format='%(asctime)s - %(levelname)s - %(message)s'
+)
+logger = logging.getLogger(__name__)
+
+class EnvisionDataReceiver:
+    def __init__(self, server_ip, server_port=2404):
+        """
+        初始化远景数据接收器
+        :param server_ip: 远景系统服务器IP
+        :param server_port: IEC104端口,默认2404
+        """
+        self.server_ip = server_ip
+        self.server_port = server_port
+        self.client = None
+
+    def on_connect(self, connection):
+        """连接成功回调"""
+        logger.info(f"成功连接到远景系统 {connection}")
+
+    def on_disconnect(self, connection):
+        """断开连接回调"""
+        logger.warning(f"与远景系统断开连接 {connection}")
+
+    def on_telemetry(self, asdu_address, io_address, value, quality, time):
+        """
+        接收遥测数据回调
+        :param asdu_address: ASDU地址
+        :param io_address: 信息对象地址
+        :param value: 值 (归一化值/标度化值/短浮点数)
+        :param quality: 质量描述符
+        :param time: 时间标签(CP56Time2a格式)
+        """
+        timestamp = time.to_datetime() if time else None
+        logger.info(f"遥测数据 - ASDU:{asdu_address} IO:{io_address} 值:{value:.2f} 质量:{quality} 时间:{timestamp}")
+
+    def on_telecommand(self, asdu_address, io_address, state, quality, time):
+        """
+        接收遥信数据回调
+        :param asdu_address: ASDU地址
+        :param io_address: 信息对象地址
+        :param state: 状态 (单点/双点)
+        :param quality: 质量描述符
+        :param time: 时间标签(CP56Time2a格式)
+        """
+        timestamp = time.to_datetime() if time else None
+        logger.info(f"遥信数据 - ASDU:{asdu_address} IO:{io_address} 状态:{state} 质量:{quality} 时间:{timestamp}")
+
+    def start(self):
+        """启动客户端连接"""
+        try:
+            # 创建IEC104客户端
+            self.client = Client()
+            self.client.add_connection(self.server_ip,self.server_port)
+
+            # 设置回调函数
+            self.client.on_connect = self.on_connect
+            self.client.on_disconnect = self.on_disconnect
+            self.client.on_telemetry = self.on_telemetry
+            self.client.on_telecommand = self.on_telecommand
+
+            # 启动连接
+            self.client.start()
+
+            logger.info(f"开始连接远景系统 {self.server_ip}:{self.server_port}...")
+
+            # 保持主线程运行
+            while True:
+                time.sleep(1)
+
+        except KeyboardInterrupt:
+            self.stop()
+        except Exception as e:
+            logger.error(f"发生错误: {str(e)}")
+            self.stop()
+            raise e
+
+    def stop(self):
+        """停止客户端"""
+        if self.client:
+            self.client.stop()
+            logger.info("已停止IEC104客户端")
+
+if __name__ == "__main__":
+    # 配置远景系统服务器IP和端口
+    ENVISION_IP = "192.168.50.242"  # 替换为远景系统实际IP
+    ENVISION_PORT = 2404
+
+    receiver = EnvisionDataReceiver(ENVISION_IP, ENVISION_PORT)
+    receiver.start()

+ 68 - 0
tmp/tmp_read_file_and_save_db.py

@@ -0,0 +1,68 @@
+import datetime
+import os
+import warnings
+
+warnings.filterwarnings("ignore")
+
+
+def __build_directory_dict(directory_dict, path, filter_types=None):
+    # 遍历目录下的所有项
+    for item in os.listdir(path):
+        item_path = os.path.join(path, item)
+        if os.path.isdir(item_path):
+            __build_directory_dict(directory_dict, item_path, filter_types=filter_types)
+        elif os.path.isfile(item_path):
+            if path not in directory_dict:
+                directory_dict[path] = []
+
+            if filter_types is None or len(filter_types) == 0:
+                directory_dict[path].append(item_path)
+            elif str(item_path).split(".")[-1] in filter_types:
+                if str(item_path).count("~$") == 0:
+                    directory_dict[path].append(item_path)
+
+
+# 读取路径下所有的excel文件
+def read_excel_files(read_path, filter_types=None):
+    if not os.path.exists(read_path):
+        return []
+
+    if filter_types is None:
+        filter_types = ['xls', 'xlsx', 'csv', 'gz']
+    if os.path.isfile(read_path):
+        return [read_path]
+
+    directory_dict = {}
+    __build_directory_dict(directory_dict, read_path, filter_types=filter_types)
+
+    return [path for paths in directory_dict.values() for path in paths if path]
+
+
+if __name__ == '__main__':
+    read_dir = r'C:\Users\wzl\Downloads\Compressed\491_盂县验证'
+    begin = datetime.datetime.now()
+    all_files = read_excel_files(read_dir)
+
+    for index, file in enumerate(all_files):
+        now_begin = datetime.datetime.now()
+
+        # 文件/home/trans/下载/盂县_data/491_盂县验证/202504/18.csv,总个数258,当前第202个写入数据库耗时:0:00:12.924708
+
+        if index < 202:
+            continue
+
+        print(index, file)
+
+        # df = pd.read_csv(file)
+        # columns_str = 'wind_turbine_number,wind_turbine_name,time_stamp,active_power,rotor_speed,generator_speed,wind_velocity,pitch_angle_blade_1,pitch_angle_blade_2,pitch_angle_blade_3,cabin_position,true_wind_direction,yaw_error1,set_value_of_active_power,gearbox_oil_temperature,generatordrive_end_bearing_temperature,generatornon_drive_end_bearing_temperature,cabin_temperature,twisted_cable_angle,front_back_vibration_of_the_cabin,side_to_side_vibration_of_the_cabin,actual_torque,given_torque,clockwise_yaw_count,counterclockwise_yaw_count,unusable,power_curve_available,required_gearbox_speed,inverter_speed_master_control,outside_cabin_temperature,main_bearing_temperature,gearbox_high_speed_shaft_bearing_temperature,gearboxmedium_speed_shaftbearing_temperature,gearbox_low_speed_shaft_bearing_temperature,generator_winding1_temperature,generator_winding2_temperature,generator_winding3_temperature,wind_turbine_status,wind_turbine_status2,turbulence_intensity,lab,year,month,day,year_month'
+        # cols = columns_str.split(',')
+        #
+        # for col in cols:
+        #     if col not in df.columns:
+        #         df[col] = np.nan
+        #
+        # trans_service.load_data_local('WOF35800082_second', df)
+        # print(
+        #     f'文件{file},总个数{len(all_files)},当前第{index + 1}个写入数据库耗时:{datetime.datetime.now() - now_begin}')
+
+    print(f'总耗时:{datetime.datetime.now() - begin}')

+ 104 - 0
tmp/use_data_generate_csv.py

@@ -0,0 +1,104 @@
+import json
+import multiprocessing
+import os
+
+
+def init_shunxu():
+
+    with open('cedian.txt', 'r') as f:
+        datas = [i.strip() for i in f.readline() if i.strip()]
+
+    result_map = dict()
+
+    for data in datas:
+        da = data.split('\t')
+        point = Mesurepoint(da[0], da[2], da[4], da[5], da[6])
+
+        if point.wind_factory in result_map.keys():
+            if point.wind_no in result_map[point.wind_factory].keys():
+                result_map[point.wind_factory][point.wind_no].append(point)
+            else:
+                result_map[point.wind_factory][point.wind_no] = [point]
+        else:
+            result_map[point.wind_factory] = {point.wind_no: [point]}
+
+    return result_map
+
+
+class Mesurepoint(object):
+
+    def __init__(self, wind_factory, wind_no, cn_name, shuxun, en_name):
+        self.wind_factory = wind_factory
+        self.wind_no = wind_no
+        self.cn_name = cn_name
+        self.shuxun = int(shuxun) + 16388
+        self.en_name = en_name
+
+
+def mult_solver(wind_factory, base_data, result_map, is_first, seconds):
+    for wind_no in result_map[wind_factory].keys():
+        shunxuhaos = [point.shuxun for point in result_map[wind_factory][wind_no]]
+        shunxuhaos.insert(0, '-1')
+        os.makedirs(os.path.join('104', wind_factory, str(seconds) + '秒'), exist_ok=True)
+        with open(os.path.join('104', wind_factory, str(seconds) + '秒', '风机号' + str(wind_no) + '.csv'),
+                  'a') as f:
+            if is_first:
+                cols = ['time']
+                for point in result_map[wind_factory][wind_no]:
+                    cols.append(point.cn_name)
+
+                f.write(",".join(cols))
+                f.write('\n')
+
+            datas = [str(base_data[str(i)]) for i in shunxuhaos]
+            f.write(",".join(datas))
+            f.write('\n')
+
+
+def save_csv(base_data, seconds, is_first=False):
+    wind_factories = result_map.keys()
+    with multiprocessing.Pool(6) as pool:
+        pool.starmap(mult_solver, [(i, base_data, result_map, is_first, seconds) for i in wind_factories])
+
+
+def generate_data(base_data, all_datas, seconds):
+    save_csv(base_data, seconds, True)
+    now_time = base_data['-1']
+    for data in all_datas:
+        data['-1'] = data['-1'].split('.')[0]
+        base_data.update(data)
+        if now_time != data['-1'] and int(data['-1'][-2:]) % seconds == 0:
+            now_time = data['-1']
+            save_csv(base_data, seconds)
+
+
+if __name__ == '__main__':
+
+    file_path = r'C:\Users\wzl\Desktop\241\2404 (复件)\20250310.txt'
+
+    result_dict = dict()
+
+    begin_end = [16388, 22744]
+    base_data = {}
+    for i in range(begin_end[0], begin_end[1] + 1):
+        base_data[str(i)] = 0
+
+    base_data['-1'] = ''
+
+    result_map = init_shunxu()
+
+    all_datas = list()
+    with open(file_path, 'r') as f:
+        line = f.readline()
+        while line:
+            fixed_str = line.replace('{', '{"').replace(':"', '":"').replace(',', ',"')
+            line_data = {}
+            line_data = json.loads(fixed_str)
+            all_datas.append(line_data)
+            line = f.readline()
+
+    generate_data(base_data, all_datas, 1)
+
+    generate_data(base_data, all_datas, 3)
+
+    generate_data(base_data, all_datas, 5)

+ 115 - 0
tmp/use_data_generate_csv11.py

@@ -0,0 +1,115 @@
+import json
+import os
+
+
+def init_shunxu():
+    with open('cedian.txt', 'r', encoding='utf8') as f:
+        datas = [i.strip() for i in f.readlines() if i.strip()]
+
+    result_map = dict()
+
+    for data in datas:
+        da = data.split('\t')
+        point = Mesurepoint(da[0], da[2], da[4], da[5], da[6])
+
+        if point.wind_factory in result_map.keys():
+            if point.wind_no in result_map[point.wind_factory].keys():
+                result_map[point.wind_factory][point.wind_no].append(point)
+            else:
+                result_map[point.wind_factory][point.wind_no] = [point]
+        else:
+            result_map[point.wind_factory] = {point.wind_no: [point]}
+
+    return result_map
+
+
+class Mesurepoint(object):
+
+    def __init__(self, wind_factory, wind_no, cn_name, shuxun, en_name):
+        self.wind_factory = wind_factory
+        self.wind_no = wind_no
+        self.cn_name = cn_name
+        self.shuxun = int(shuxun) + 16388
+        self.en_name = en_name
+
+
+def mult_solver(wind_maps, seconds):
+    for wind_factory in wind_maps.keys():
+        for wind_no in wind_maps[wind_factory].keys():
+            file_dir = os.path.join('104', wind_factory, str(seconds) + '秒')
+            os.makedirs(file_dir, exist_ok=True)
+            line_str = '\n'.join(wind_maps[wind_factory][wind_no])
+            with open(os.path.join(file_dir, '风机' + str(wind_no) + '.csv'), 'w') as f:
+                f.write(line_str)
+                f.flush()
+
+
+def gene_data(wind_maps, base_data):
+    wind_factories = result_map.keys()
+    for wind_factory in wind_factories:
+
+        if wind_factory not in wind_maps.keys():
+            wind_maps[wind_factory] = {}
+
+        for wind_no in result_map[wind_factory].keys():
+            is_first = False
+            if wind_no not in wind_maps[wind_factory].keys():
+                wind_maps[wind_factory][wind_no] = list()
+                is_first = True
+
+            shunxuhaos = [point.shuxun for point in result_map[wind_factory][wind_no]]
+            shunxuhaos.insert(0, '-1')
+
+            if is_first:
+                cols = ['time']
+                for point in result_map[wind_factory][wind_no]:
+                    cols.append(point.cn_name)
+                wind_maps[wind_factory][wind_no].append(','.join(cols))
+
+            datas = [str(base_data[str(i)]) for i in shunxuhaos]
+            wind_maps[wind_factory][wind_no].append(','.join(datas))
+
+
+def generate_data(base_data, all_datas, seconds):
+    now_time = base_data['-1']
+    wind_maps = dict()
+    for data in all_datas:
+        data['-1'] = data['-1'].split('.')[0]
+        base_data.update(data)
+        if now_time != data['-1'] and int(data['-1'][-2:]) % seconds == 0:
+            now_time = data['-1']
+            gene_data(wind_maps, base_data)
+
+    mult_solver(wind_maps, seconds)
+
+
+if __name__ == '__main__':
+
+    file_path = r'C:\Users\wzl\Desktop\241\2404 (复件)\20250310.txt'
+
+    result_dict = dict()
+
+    begin_end = [16388, 22744]
+    base_data = {}
+    for i in range(begin_end[0], begin_end[1] + 1):
+        base_data[str(i)] = 0
+
+    base_data['-1'] = ''
+
+    result_map = init_shunxu()
+
+    all_datas = list()
+    with open(file_path, 'r') as f:
+        line = f.readline()
+        while line:
+            fixed_str = line.replace('{', '{"').replace(':"', '":"').replace(',', ',"')
+            line_data = {}
+            line_data = json.loads(fixed_str)
+            all_datas.append(line_data)
+            line = f.readline()
+
+    generate_data(base_data, all_datas, 1)
+
+    generate_data(base_data, all_datas, 3)
+
+    generate_data(base_data, all_datas, 5)

+ 104 - 0
tmp/use_data_generate_csv12.py

@@ -0,0 +1,104 @@
+import json
+import os
+
+
+def init_shunxu():
+    with open('cedian.txt', 'r', encoding='utf8') as f:
+        datas = [i.strip() for i in f.readlines() if i.strip()]
+
+    result_map = dict()
+
+    for data in datas:
+        da = data.split('\t')
+        point = Mesurepoint(da[0], da[2], da[4], da[5], da[6])
+
+        if point.wind_factory in result_map.keys():
+            if point.wind_no in result_map[point.wind_factory].keys():
+                result_map[point.wind_factory][point.wind_no].append(point)
+            else:
+                result_map[point.wind_factory][point.wind_no] = [point]
+        else:
+            result_map[point.wind_factory] = {point.wind_no: [point]}
+
+    return result_map
+
+
+class Mesurepoint(object):
+
+    def __init__(self, wind_factory, wind_no, cn_name, shuxun, en_name):
+        self.wind_factory = wind_factory
+        self.wind_no = wind_no
+        self.cn_name = cn_name
+        self.shuxun = int(shuxun) + 16388
+        self.en_name = en_name
+
+
+def mult_solver(wind_maps):
+    for wind_factory in wind_maps.keys():
+        for wind_no in wind_maps[wind_factory].keys():
+            file_dir = os.path.join('104_origin', wind_factory)
+            os.makedirs(file_dir, exist_ok=True)
+            line_str = '\n'.join(wind_maps[wind_factory][wind_no])
+            with open(os.path.join(file_dir, '风机' + str(wind_no) + '.csv'), 'w') as f:
+                f.write(line_str)
+                f.flush()
+
+
+def gene_data(wind_maps, data):
+    wind_factories = result_map.keys()
+    for wind_factory in wind_factories:
+
+        if wind_factory not in wind_maps.keys():
+            wind_maps[wind_factory] = {}
+
+        for wind_no in result_map[wind_factory].keys():
+            is_first = False
+            if wind_no not in wind_maps[wind_factory].keys():
+                wind_maps[wind_factory][wind_no] = list()
+                is_first = True
+
+            shunxuhaos = [point.shuxun for point in result_map[wind_factory][wind_no]]
+            shunxuhaos.insert(0, '-1')
+
+            if is_first:
+                cols = ['time']
+                for point in result_map[wind_factory][wind_no]:
+                    cols.append(point.cn_name)
+                wind_maps[wind_factory][wind_no].append(','.join(cols))
+
+            datas = [str(data[str(i)] if str(i) in data.keys() else "") for i in shunxuhaos]
+            if len([i for i in datas if i != ""]) > 1:
+                wind_maps[wind_factory][wind_no].append(','.join(datas))
+
+
+def generate_data(all_datas):
+    wind_maps = dict()
+    for data in all_datas:
+        gene_data(wind_maps, data)
+
+    mult_solver(wind_maps)
+
+
+if __name__ == '__main__':
+
+    # file_path = r'C:\Users\wzl\Desktop\241\2404 (复件)\20250310.txt'
+
+    file_path = '原始数据.txt'
+
+    result_dict = dict()
+
+    begin_end = [16388, 22744]
+
+    result_map = init_shunxu()
+
+    all_datas = list()
+    with open(file_path, 'r') as f:
+        line = f.readline()
+        while line:
+            fixed_str = line.replace('{', '{"').replace(':"', '":"').replace(',', ',"')
+            line_data = {}
+            line_data = json.loads(fixed_str)
+            all_datas.append(line_data)
+            line = f.readline()
+
+    generate_data(all_datas)

+ 20 - 0
tmp/warn_fault_yaml.py

@@ -0,0 +1,20 @@
+import pandas as pd
+import yaml
+
+df = pd.read_excel(r'C:\Users\wzl\Desktop\中广核104测点\0416部署需要\故障报警\故障代码表.xlsx')
+
+result_json = dict()
+
+for index, row in df.iterrows():
+    mc_id = row['主控ID'].strip()
+    code = row['状态编码']
+    en_name = row['SC中文描述'].strip()
+    level = str(row['告警等级']).strip()
+    if mc_id in result_json.keys():
+        result_json[mc_id][code] = {'en_name': en_name, 'level': level}
+    else:
+        result_json[mc_id] = {code: {'en_name': en_name, 'level': level}}
+
+yaml_str = yaml.dump(result_json, allow_unicode=True, sort_keys=False)
+with open('warn_fault.yaml', 'w', encoding='utf8') as f:
+    f.write(yaml_str)

+ 104 - 0
tmp/zhuanhua.py

@@ -0,0 +1,104 @@
+import json
+import multiprocessing
+import os
+
+
+def init_shunxu():
+
+    with open('cedian.txt', 'r') as f:
+        datas = [i.strip() for i in f.readline() if i.strip()]
+
+    result_map = dict()
+
+    for data in datas:
+        da = data.split('\t')
+        point = Mesurepoint(da[0], da[2], da[4], da[5], da[6])
+
+        if point.wind_factory in result_map.keys():
+            if point.wind_no in result_map[point.wind_factory].keys():
+                result_map[point.wind_factory][point.wind_no].append(point)
+            else:
+                result_map[point.wind_factory][point.wind_no] = [point]
+        else:
+            result_map[point.wind_factory] = {point.wind_no: [point]}
+
+    return result_map
+
+
+class Mesurepoint(object):
+
+    def __init__(self, wind_factory, wind_no, cn_name, shuxun, en_name):
+        self.wind_factory = wind_factory
+        self.wind_no = wind_no
+        self.cn_name = cn_name
+        self.shuxun = int(shuxun) + 16388
+        self.en_name = en_name
+
+
+def mult_solver(wind_factory, base_data, result_map, is_first, seconds):
+    for wind_no in result_map[wind_factory].keys():
+        shunxuhaos = [point.shuxun for point in result_map[wind_factory][wind_no]]
+        shunxuhaos.insert(0, '-1')
+        os.makedirs(os.path.join('104', wind_factory, str(seconds) + '秒'), exist_ok=True)
+        with open(os.path.join('104', wind_factory, str(seconds) + '秒', '风机号' + str(wind_no) + '.csv'),
+                  'a') as f:
+            if is_first:
+                cols = ['time']
+                for point in result_map[wind_factory][wind_no]:
+                    cols.append(point.cn_name)
+
+                f.write(",".join(cols))
+                f.write('\n')
+
+            datas = [str(base_data[str(i)]) for i in shunxuhaos]
+            f.write(",".join(datas))
+            f.write('\n')
+
+
+def save_csv(base_data, seconds, is_first=False):
+    wind_factories = result_map.keys()
+    with multiprocessing.Pool(6) as pool:
+        pool.starmap(mult_solver, [(i, base_data, result_map, is_first, seconds) for i in wind_factories])
+
+
+def generate_data(base_data, all_datas, seconds):
+    save_csv(base_data, seconds, True)
+    now_time = base_data['-1']
+    for data in all_datas:
+        data['-1'] = data['-1'].split('.')[0]
+        base_data.update(data)
+        if now_time != data['-1'] and int(data['-1'][-2:]) % seconds == 0:
+            now_time = data['-1']
+            save_csv(base_data, seconds)
+
+
+if __name__ == '__main__':
+
+    file_path = r'C:\Users\wzl\Desktop\241\2404 (复件)\20250310.txt'
+
+    result_dict = dict()
+
+    begin_end = [16388, 22744]
+    base_data = {}
+    for i in range(begin_end[0], begin_end[1] + 1):
+        base_data[str(i)] = 0
+
+    base_data['-1'] = ''
+
+    result_map = init_shunxu()
+
+    all_datas = list()
+    with open(file_path, 'r') as f:
+        line = f.readline()
+        while line:
+            fixed_str = line.replace('{', '{"').replace(':"', '":"').replace(',', ',"')
+            line_data = {}
+            line_data = json.loads(fixed_str)
+            all_datas.append(line_data)
+            line = f.readline()
+
+    generate_data(base_data, all_datas, 1)
+
+    generate_data(base_data, all_datas, 3)
+
+    generate_data(base_data, all_datas, 5)

+ 12 - 0
tmp/再次导入数据.py

@@ -0,0 +1,12 @@
+import os
+
+import pandas as pd
+
+from service import trans_service
+
+read_dir = r'C:\Users\wzl\Downloads\Compressed\490_盂县验证\2025'
+
+for file in os.listdir(read_dir):
+    df = pd.read_csv(os.path.join(read_dir, file))
+    trans_service.save_df_to_db('WOF35800082_minute', df)
+    print(file, '执行完成')

+ 357 - 0
tmp/文档生成器.py

@@ -0,0 +1,357 @@
+import os
+import platform
+import tempfile
+from typing import List, Dict, Tuple, Optional
+
+import matplotlib.pyplot as plt
+import numpy as np
+from docx import Document
+from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
+from docx.oxml.ns import qn
+from docx.oxml.shared import OxmlElement
+from docx.shared import Inches, Pt, RGBColor
+from matplotlib import font_manager
+
+
+class DocxGenerator:
+    def __init__(self, filename: str = "output.docx"):
+        """
+        初始化文档生成器
+
+        :param filename: 输出文件名
+        """
+        self.document = Document()
+        self.filename = filename
+        self.temp_files = []  # 用于存储临时文件路径
+
+        # 设置默认字体
+        self._set_default_font()
+
+        # 设置matplotlib中文字体
+        self._set_matplotlib_font()
+
+    def _set_default_font(self):
+        """设置文档默认字体"""
+        style = self.document.styles['Normal']
+        font = style.font
+        font.name = '微软雅黑'
+        font.size = Pt(10.5)
+
+    def _set_matplotlib_font(self):
+        """设置matplotlib中文字体"""
+        # 根据操作系统选择字体
+        system = platform.system()
+
+        if system == 'Windows':
+            # Windows系统通常有微软雅黑
+            plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 设置字体为微软雅黑
+        elif system == 'Darwin':
+            # Mac系统通常有PingFang SC
+            plt.rcParams['font.sans-serif'] = ['PingFang SC']  # 设置字体为苹方
+        else:
+            # Linux系统尝试使用文泉驿微米黑
+            plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei']  # 设置字体为文泉驿微米黑
+
+        plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
+
+        # 如果上述字体不存在,尝试查找系统中可用的中文字体
+        try:
+            # 查找系统中可用的中文字体
+            chinese_fonts = [f.name for f in font_manager.fontManager.ttflist
+                             if 'Hei' in f.name or 'hei' in f.name or
+                             'YaHei' in f.name or 'yahei' in f.name or
+                             'Song' in f.name or 'song' in f.name or
+                             'Kai' in f.name or 'kai' in f.name or
+                             'Fang' in f.name or 'fang' in f.name]
+
+            if chinese_fonts:
+                plt.rcParams['font.sans-serif'] = [chinese_fonts[0]]
+        except:
+            pass
+
+    def add_title(self, text: str, level: int = 1):
+        """
+        添加标题
+
+        :param text: 标题文本
+        :param level: 标题级别 (1-3)
+        """
+        if level == 1:
+            self.document.add_heading(text, level=0)
+        elif level == 2:
+            self.document.add_heading(text, level=1)
+        elif level == 3:
+            self.document.add_heading(text, level=2)
+        else:
+            self.document.add_heading(text, level=2)
+
+    def add_paragraph(self, text: str, bold: bool = False, italic: bool = False,
+                      underline: bool = False, color: Optional[Tuple[int, int, int]] = None,
+                      alignment: str = "left"):
+        """
+        添加段落文本
+
+        :param text: 文本内容
+        :param bold: 是否加粗
+        :param italic: 是否斜体
+        :param underline: 是否下划线
+        :param color: 文字颜色 (R, G, B)
+        :param alignment: 对齐方式 ("left", "center", "right", "justify")
+        """
+        paragraph = self.document.add_paragraph()
+
+        # 设置对齐方式
+        if alignment == "center":
+            paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
+        elif alignment == "right":
+            paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
+        elif alignment == "justify":
+            paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
+        else:
+            paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
+
+        run = paragraph.add_run(text)
+        run.bold = bold
+        run.italic = italic
+        run.underline = underline
+
+        if color:
+            run.font.color.rgb = RGBColor(*color)
+
+    def add_line_break(self):
+        """添加换行"""
+        self.document.add_paragraph()
+
+    def add_page_break(self):
+        """添加分页符"""
+        self.document.add_page_break()
+
+    def _save_plot_to_tempfile(self, plt_obj):
+        """保存matplotlib图表到临时文件"""
+        temp_file = tempfile.NamedTemporaryFile(suffix=".png", delete=False)
+        self.temp_files.append(temp_file.name)
+        plt_obj.savefig(temp_file.name, dpi=300, bbox_inches='tight')
+        plt.close()
+        return temp_file.name
+
+    def add_line_chart(self, title: str, categories: List[str], series: Dict[str, List[float]],
+                       width: float = 6, height: float = 4):
+        """
+        添加折线图
+
+        :param title: 图表标题
+        :param categories: 类别列表 (x轴)
+        :param series: 数据系列字典 {系列名: 数据列表}
+        :param width: 图表宽度 (英寸)
+        :param height: 图表高度 (英寸)
+        """
+        plt.figure(figsize=(width, height))
+
+        for name, values in series.items():
+            plt.plot(categories, values, marker='o', label=name)
+
+        plt.title(title, fontproperties=self._get_chinese_font())
+        plt.xlabel('分类', fontproperties=self._get_chinese_font())
+        plt.ylabel('数值', fontproperties=self._get_chinese_font())
+        plt.legend(prop=self._get_chinese_font())
+        plt.grid(True)
+
+        # 保存图表并插入到文档
+        temp_file = self._save_plot_to_tempfile(plt)
+        self._add_image_to_doc(temp_file, width, height, title)
+
+    def add_pie_chart(self, title: str, data: Dict[str, float],
+                      width: float = 6, height: float = 4):
+        """
+        添加饼图
+
+        :param title: 图表标题
+        :param data: 数据字典 {标签: 值}
+        :param width: 图表宽度 (英寸)
+        :param height: 图表高度 (英寸)
+        """
+        plt.figure(figsize=(width, height))
+
+        labels = list(data.keys())
+        sizes = list(data.values())
+
+        plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90,
+                textprops={'fontproperties': self._get_chinese_font()})
+        plt.axis('equal')  # 保持圆形
+        plt.title(title, fontproperties=self._get_chinese_font())
+
+        # 保存图表并插入到文档
+        temp_file = self._save_plot_to_tempfile(plt)
+        self._add_image_to_doc(temp_file, width, height, title)
+
+    def add_rose_chart(self, title: str, data: Dict[str, float],
+                       width: float = 6, height: float = 4):
+        """
+        添加玫瑰图 (极坐标条形图)
+
+        :param title: 图表标题
+        :param data: 数据字典 {标签: 值}
+        :param width: 图表宽度 (英寸)
+        :param height: 图表高度 (英寸)
+        """
+        plt.figure(figsize=(width, height))
+
+        labels = list(data.keys())
+        values = list(data.values())
+        N = len(labels)
+
+        theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
+        radii = values
+        width = 2 * np.pi / N * 0.8
+
+        ax = plt.subplot(111, polar=True)
+        bars = ax.bar(theta, radii, width=width, bottom=0.0)
+
+        # 设置标签
+        ax.set_xticks(theta)
+        ax.set_xticklabels(labels, fontproperties=self._get_chinese_font())
+        ax.set_title(title, fontproperties=self._get_chinese_font())
+
+        # 设置颜色
+        for r, bar in zip(radii, bars):
+            bar.set_facecolor(plt.cm.viridis(r / max(radii)))
+            bar.set_alpha(0.8)
+
+        # 保存图表并插入到文档
+        temp_file = self._save_plot_to_tempfile(plt)
+        self._add_image_to_doc(temp_file, height, height, title)
+
+    def _get_chinese_font(self):
+        """获取中文字体属性"""
+        from matplotlib.font_manager import FontProperties
+        system = platform.system()
+
+        if system == 'Windows':
+            return FontProperties(fname='C:/Windows/Fonts/msyh.ttc', size=12)  # 微软雅黑
+        elif system == 'Darwin':
+            return FontProperties(fname='/System/Library/Fonts/PingFang.ttc', size=12)  # 苹方
+        else:
+            return FontProperties(fname='/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc', size=12)  # 文泉驿微米黑
+
+    def _add_image_to_doc(self, image_path: str, width: float, height: float, title: str = None):
+        """将图片添加到文档"""
+        paragraph = self.document.add_paragraph()
+        run = paragraph.add_run()
+        run.add_picture(image_path, width=Inches(width), height=Inches(height))
+
+        # 添加图表标题
+        if title:
+            self.add_paragraph(f"图: {title}", alignment="center")
+
+    def add_table(self, data: List[List[str]], header: bool = True):
+        """
+        添加表格
+
+        :param data: 表格数据 (二维列表)
+        :param header: 第一行是否为表头
+        """
+        table = self.document.add_table(rows=len(data), cols=len(data[0]))
+
+        for i, row in enumerate(data):
+            for j, cell in enumerate(row):
+                table.cell(i, j).text = cell
+
+        # 设置表头样式
+        if header and len(data) > 0:
+            for j in range(len(data[0])):
+                table.cell(0, j).paragraphs[0].runs[0].bold = True
+
+                # 设置表头背景色
+                shading_elm = OxmlElement('w:shd')
+                shading_elm.set(qn('w:fill'), 'D9D9D9')
+                table.cell(0, j)._tc.get_or_add_tcPr().append(shading_elm)
+
+    def generate(self):
+        """
+        生成并保存文档
+
+        :return: 生成的文件路径
+        """
+        # 保存文档
+        self.document.save(self.filename)
+
+        # 清理临时文件
+        for temp_file in self.temp_files:
+            try:
+                os.unlink(temp_file)
+            except:
+                pass
+
+        return self.filename
+
+
+# 使用示例
+if __name__ == "__main__":
+    # 创建文档生成器
+    doc = DocxGenerator("示例文档1.docx")
+
+    # 添加标题
+    doc.add_title("年度销售报告", level=1)
+    doc.add_line_break()
+
+    # 添加段落
+    doc.add_paragraph("本报告展示公司2023年度的销售情况分析。", bold=True)
+    doc.add_paragraph("报告包含以下内容:")
+    doc.add_paragraph("1. 各季度销售趋势", color=(0, 0, 255))
+    doc.add_paragraph("2. 产品销售占比", color=(0, 0, 255))
+    doc.add_paragraph("3. 区域销售分布", color=(0, 0, 255))
+    doc.add_line_break()
+    doc.add_paragraph("""
+    1. 各季度销售趋势
+    2. 产品销售占比
+    3. 区域销售分布
+    """, color=(0, 0, 255))
+    doc.add_line_break()
+
+    # 添加折线图
+    doc.add_title("季度销售趋势", level=2)
+    categories = ["第一季度", "第二季度", "第三季度", "第四季度"]
+    series = {
+        "产品A": [120, 150, 180, 200],
+        "产品B": [80, 90, 110, 130],
+        "产品C": [50, 70, 90, 100]
+    }
+    doc.add_line_chart("季度销售趋势", categories, series)
+    doc.add_line_break()
+
+    # 添加饼图
+    doc.add_title("产品销售占比", level=2)
+    pie_data = {
+        "产品A": 45,
+        "产品B": 30,
+        "产品C": 25
+    }
+    doc.add_pie_chart("产品销售占比", pie_data)
+    doc.add_line_break()
+
+    # 添加玫瑰图
+    doc.add_title("区域销售分布", level=2)
+    rose_data = {
+        "华东地区": 35,
+        "华北地区": 25,
+        "华南地区": 20,
+        "西部地区": 15,
+        "东北地区": 5
+    }
+    doc.add_rose_chart("区域销售分布", rose_data)
+    doc.add_line_break()
+
+    # 添加表格
+    doc.add_title("详细销售数据", level=2)
+    table_data = [
+        ["季度", "产品A", "产品B", "产品C", "总计"],
+        ["第一季度", "120", "80", "50", "250"],
+        ["第二季度", "150", "90", "70", "310"],
+        ["第三季度", "180", "110", "90", "380"],
+        ["第四季度", "200", "130", "100", "430"]
+    ]
+    doc.add_table(table_data)
+
+    # 生成文档
+    output_file = doc.generate()
+    print(f"文档已生成: {output_file}")

+ 58 - 0
tmp/测点转化为yaml.py

@@ -0,0 +1,58 @@
+import pandas as pd
+
+df = pd.read_excel(r'C:\Users\wzl\Desktop\中广核104测点\0416部署需要\最终测点配置.xlsx',
+                   usecols=['标准化中文', '遥测别名', 'en_name', '场站', '风机号'])
+
+df['场站'] = df['场站'].apply(lambda x: x if x != '富风' else '太古')
+df['风机号'] = df['风机号'].apply(lambda x: int(x.split('WTG')))
+df['风机号'] = df.apply(lambda x: int(x.split('WTG')))
+
+# data_dict = dict()
+#
+# for _, data in df.iterrows():
+#     cn_name = data['标准化中文']
+#     bie_ming = data['遥测别名']
+#     en_name = data['en_name']
+#     changzhan = data['场站'] if data['场站'] != '富风' else '太古'
+#     wind_no = int(data['风机号'].split('WTG')) if changzhan != '坡底' else data['风机号'].replace('WTG', 'F')
+
+#     if changzhan in data_dict.keys():
+#
+#         if wind_no in data_dict[changzhan].keys():
+#             data_dict[changzhan][wind_no].append((bie_ming, cn_name, en_name))
+#         else:
+#             data_dict[changzhan][wind_no] = [(bie_ming, cn_name, en_name)]
+#     else:
+#         data_dict[changzhan] = {wind_no: [(bie_ming, cn_name, en_name)]}
+#
+# result = dict()
+# result_list = list()
+# shunxuhao = 0
+# for k, v in data_dict.items():
+#     result_dict = dict()
+#     result_dict['wind_factory'] = dict()
+#     result_dict['wind_factory']['cn_name'] = k
+#     result_dict['wind_factory']['wind_factory_no'] = ''
+#     wind_turbine_list = list()
+#     for k1, v1 in v.items():
+#         wind_turbine_dict = dict()
+#         wind_turbine_dict['wind_turbine_number'] = k1
+#         wind_turbine_dict['measurepoints'] = list()
+#         for v2 in v1:
+#             point_dict = dict()
+#             point_dict['point'] = dict()
+#             point_dict['point']['shunxuhao'] = shunxuhao
+#             shunxuhao = shunxuhao + 1
+#             point_dict['point']['yc_name'] = v2[0]
+#             point_dict['point']['standerd_cn_name'] = v2[1]
+#             point_dict['point']['standerd_en_name'] = v2[2]
+#             wind_turbine_dict['measurepoints'].append(point_dict)
+#
+#         wind_turbine_list.append(wind_turbine_dict)
+#     result_dict['wind_factory']['wind_turbine'] = wind_turbine_list
+#     result_list.append(result_dict)
+# result['wind_factories'] = result_list
+#
+# yaml_str = yaml.dump(result, allow_unicode=True, sort_keys=False)
+# with open('mesurepoint.yaml', 'w', encoding='utf8') as f:
+#     f.write(yaml_str)

+ 63 - 0
tmp/生成测试数据.py

@@ -0,0 +1,63 @@
+from datetime import datetime, timedelta
+
+import numpy as np
+import pandas as pd
+
+
+def main():
+    # 设置参数
+    num_rows = 600  # 示例数据行数
+    num_cols = 14118
+
+    # 创建时间戳列(第0列)
+    start_date = datetime(2023, 1, 1, 0, 10, 0)
+    timestamps = [str(start_date + timedelta(seconds=i)) for i in range(num_rows)]
+
+    # 创建浮点型数据列(第1-10229列)
+    float_data = np.random.uniform(low=0.0, high=100.0, size=(num_rows, 10229))
+
+    # 创建整型数据列(前部分:10230-14117中的前一部分)
+    # 假设前2000个整型列范围[100001,700001]
+    int_data_part1 = np.random.randint(low=100001, high=700002, size=(num_rows, 2000))
+
+    # 剩下的整型列范围[-5,1000]
+    remaining_int_cols = num_cols - 10230 - 2000
+    int_data_part2 = np.random.randint(low=-5, high=1001, size=(num_rows, remaining_int_cols))
+
+    # 合并所有数据
+    all_data = np.hstack([
+        np.array(timestamps).reshape(-1, 1),  # 时间戳列
+        float_data,  # 浮点型数据
+        int_data_part1,  # 第一段整型数据
+        int_data_part2  # 第二段整型数据
+    ])
+
+    # 创建列名
+    col_names = ['timestamp']
+    col_names += [f'float_{i}' for i in range(1, 10230)]
+    col_names += [f'int_part1_{i}' for i in range(10230, 10230 + 2000)]
+    col_names += [f'int_part2_{i}' for i in range(10230 + 2000, 14118)]
+
+    # 创建DataFrame
+    df = pd.DataFrame(all_data, columns=col_names)
+
+    # 设置正确的数据类型
+    df['timestamp'] = pd.to_datetime(df['timestamp'])
+    for col in df.columns[1:10230]:
+        df[col] = df[col].astype(float)
+    for col in df.columns[10230:]:
+        df[col] = df[col].astype(int)
+
+    print(df.columns)
+    print(df.shape)
+    print(df.info())
+
+    df.to_csv('../conf/test.csv', header=None, index=False, encoding='utf8')
+
+
+if __name__ == '__main__':
+    import time
+
+    begin = time.time()
+    main()
+    print(time.time() - begin)

+ 88 - 0
tmp/转发顺序号处理.py

@@ -0,0 +1,88 @@
+import pandas as pd
+
+fengchang_map = {
+    '平陆': 'WOF35900004', '阳曲': 'WOF35100072', '古交': 'WOF35100073', '马家梁': 'WOF35200074',
+    '太谷': 'WOF35400075', '坡底': 'WOF35900076', '西潘': 'WOF35300077', '芮城': 'WOF35900078',
+    '右玉': 'WOF34900079', '贺家沟': 'WOF35800080', '石楼': 'WOF35800081', '盂县': 'WOF35800082',
+    '富风': 'WOF35400075'
+}
+
+wind_farms = {
+    "WOF35900004": "平陆风电场",
+    "WOF35100072": "阳曲风电场",
+    "WOF35100073": "古交风电场",
+    "WOF35200074": "马家梁风电场",
+    "WOF35400075": "太谷风电场",
+    "WOF35900076": "坡底风电场",
+    "WOF35300077": "西潘风电场",
+    "WOF35900078": "芮城风电场",
+    "WOF34900079": "右玉风光互补电站",
+    "WOF35800080": "贺家沟",
+    "WOF35800081": "石楼风电场",
+    "WOF35800082": "盂县风光互补电站"
+}
+
+
+def generate_sacada_conf(all_df, cedian_df):
+    cedian_df['场站标准化编号'] = cedian_df['场站'].map(fengchang_map)
+    cedian_df['场站'] = cedian_df['场站标准化编号'].map(wind_farms)
+
+    cedian_df['风机号'] = cedian_df['风机号'].apply(lambda x: int(x[-3:]))
+
+    df2404 = all_df[all_df['转发逻辑设备ID号'] == '转发到二区2404 ']
+    df2405 = all_df[all_df['转发逻辑设备ID号'] == '转发到二区2405 ']
+
+    df2404 = pd.merge(df2404, cedian_df, left_on='遥测ID号', right_on='遥测名称', how='inner')
+    df2405 = pd.merge(df2405, cedian_df, left_on='遥测ID号', right_on='遥测名称', how='inner')
+
+    del df2404['Unnamed: 0']
+    del df2405['Unnamed: 0']
+
+    ## 顺序号,场站,场站标准化编号,风机号,遥测别名,标准化中文,标准化英文
+
+    name_dict = {
+        "转发顺序号": "顺序号",
+        "en_name": "标准化英文"
+    }
+
+    df2404.rename(columns=name_dict, inplace=True)
+    df2405.rename(columns=name_dict, inplace=True)
+
+    select_cols = ["顺序号", "遥测ID号", "场站", "场站标准化编号", "风机号", "遥测别名", "标准化中文", "标准化英文"]
+
+    df2404[select_cols].to_excel('../conf/测点表-2404.xlsx', index=False)
+    df2405[select_cols].to_excel('../conf/测点表-2405.xlsx', index=False)
+
+
+def generate_warn_fault_conf(all_df: pd.DataFrame, warn_fault_df: pd.DataFrame):
+    del warn_fault_df['顺序号']
+    df2406 = all_df[all_df['转发逻辑设备ID号'] == '转发到二区2406 ']
+    df2406['顺序号'] = df2406['转发顺序号']
+    df2406.drop_duplicates(inplace=True)
+    df2406 = pd.merge(df2406, warn_fault_df, left_on='遥测ID号', right_on='遥测名称', how='inner')
+    select_cols = ["顺序号", "场站", "场站标准化编号", "风机号", "遥测名称", "遥测别名"]
+    df2406[select_cols].to_excel('../conf/故障报警测点-2406.xlsx', index=False)
+
+
+def generate_warn_fault_mc_version(mc_version_df):
+    mc_version_df['场站标准化编号'] = mc_version_df['场站'].map(fengchang_map)
+    mc_version_df['场站'] = mc_version_df['场站标准化编号'].map(wind_farms)
+    mc_version_df.to_excel('../conf/主控版本-2406.xlsx', index=False)
+
+
+if __name__ == '__main__':
+    all_df = pd.read_excel(r'C:\Users\wzl\Desktop\fault_20240423.xlsx')
+    all_df['遥测ID号'] = all_df['遥测ID号'].apply(lambda x: x.replace('遥测定义表', '').replace('遥测值', '').strip())
+    all_df = all_df[['遥测ID号', '转发逻辑设备ID号', '转发顺序号']]
+
+    # ## 配置scada 配置文件
+    # cedian_df = pd.read_excel(r'C:\Users\wzl\Desktop\中广核104测点\0416部署需要\最终测点配置.xlsx')
+    # generate_sacada_conf(all_df, cedian_df)
+
+    ## 配置故障报警 配置文件
+    warn_fault_df = pd.read_excel(r'D:\project\energy-online-data\conf\故障报警测点.xlsx')
+    generate_warn_fault_conf(all_df, warn_fault_df)
+
+    ## 主控版本处理
+    # mc_version_df = pd.read_excel(r'D:\project\energy-online-data\conf\主控版本.xlsx')
+    # generate_warn_fault_mc_version(mc_version_df)

+ 47 - 0
tmp/风场映射.py

@@ -0,0 +1,47 @@
+import time
+
+import pandas as pd
+
+fengchang_map = {'平陆': 'WOF35900004', '阳曲': 'WOF35100072', '古交': 'WOF35100073', '马家梁': 'WOF35200074',
+                 '太谷': 'WOF35200075', '坡底': 'WOF35900076', '西潘': 'WOF35300077', '芮城': 'WOF35900078',
+                 '右玉': 'WOF34900079', '贺家沟': 'WOF35800080', '石楼': 'WOF35800081', '盂县': 'WOF35800082',
+                 '富风': 'WOF35200075'
+                 }
+
+wind_farms = {
+    "WOF35900004": "平陆风电场",
+    "WOF35100072": "阳曲风电场",
+    "WOF35100073": "古交风电场",
+    "WOF35200074": "马家梁风电场",
+    "WOF35400075": "太谷风电场",
+    "WOF35900076": "坡底风电场",
+    "WOF35300077": "西潘风电场",
+    "WOF35900078": "芮城风电场",
+    "WOF34900079": "右玉风光互补电站",
+    "WOF35800080": "贺家沟",
+    "WOF35800081": "石楼风电场",
+    "WOF35800082": "盂县风光互补电站"
+}
+
+begin = time.time()
+df = pd.read_excel(r'C:\Users\wzl\Desktop\中广核104测点\0416部署需要\最终测点配置.xlsx')
+print(time.time() - begin)
+
+selet_cols = ['场站', '风机号', '标准化中文', '遥测别名', 'en_name']
+
+now_df = df[selet_cols]
+
+now_df['场站'] = now_df['场站'].apply(lambda x: x if x != '富风' else '太古')
+
+now_df['场站标准化编号'] = df['场站'].map(fengchang_map)
+
+now_df['风机号'] = now_df['风机号'].apply(lambda x: int(x.replace('WTG', '')))
+
+now_df.reset_index(inplace=True)
+now_df.rename(columns={'en_name': '标准化英文', 'index': '顺序号'}, inplace=True)
+
+result_select = ['顺序号', '场站', '场站标准化编号', '风机号', '遥测别名', '标准化中文', '标准化英文']
+
+print(now_df[result_select])
+
+now_df[result_select].to_excel('../conf/测点表.xlsx', columns=result_select, index=False)

+ 3 - 0
utils/__init__.py

@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/6/6
+# @Author  : 魏志亮

+ 3 - 0
utils/conf/__init__.py

@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/6/7
+# @Author  : 魏志亮

+ 22 - 0
utils/conf/read_conf.py

@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/6/7
+# @Author  : 魏志亮
+
+import yaml
+
+
+def yaml_conf(path, encoding='utf-8'):
+    with open(path, 'r', encoding=encoding) as f:
+        data = yaml.safe_load(f)
+    return data
+
+
+def read_conf(dict_conf, col, default_value=None):
+    if col in dict_conf:
+        res = dict_conf[col]
+        if res is None and default_value is not None:
+            return default_value
+        return res
+    else:
+        return default_value
+

+ 109 - 0
utils/db/ConnectMysql.py

@@ -0,0 +1,109 @@
+import tempfile
+import time
+import traceback
+from os import *
+
+import pandas as pd
+import pymysql
+from pymysql.cursors import DictCursor
+from sqlalchemy import create_engine, text
+
+from utils.conf.read_conf import yaml_conf
+from utils.log.trans_log import logger
+
+
+class ConnectMysql:
+
+    def __init__(self, connet_name):
+        conf_path = path.abspath(__file__).split("utils")[0] + 'conf' + sep + 'config.yaml'
+        self.yaml_data = yaml_conf(conf_path)
+        self.connet_name = connet_name
+        self.config = self.yaml_data[self.connet_name]
+        self.database = self.config['database']
+
+    # 从连接池中获取一个连接
+    def get_conn(self):
+        return pymysql.connect(**self.config, local_infile=True)
+
+    # 使用连接执行sql
+    def execute(self, sql, params=tuple()):
+
+        with self.get_conn() as conn:
+            with conn.cursor(cursor=DictCursor) as cursor:
+                try:
+                    cursor.execute(sql, params)
+                    logger.info(f"开始执行SQL:{cursor._executed}")
+                    conn.commit()
+                    result = cursor.fetchall()
+                    return result
+                except Exception as e:
+                    logger.info(f"执行sql:{sql},报错:{e}")
+                    logger.info(traceback.format_exc())
+                    conn.rollback()
+                    raise e
+
+    def get_engine(self):
+        config = self.config
+        username = config['user']
+        password = config['password']
+        host = config['host']
+        port = config['port']
+        dbname = config['database']
+        return create_engine(f'mysql+pymysql://{username}:{password}@{host}:{port}/{dbname}?local_infile=1')
+
+    def execute_df_save(self, df, table_name, batch_count=1000):
+        df.to_sql(table_name, self.get_engine(), index=False, if_exists='append', chunksize=batch_count)
+
+    def read_sql_to_df(self, sql):
+        df = pd.read_sql_query(sql, self.get_engine())
+        return df
+
+
+    def safe_load_data_local(self, df, table_name, batch_size=30000):
+        """
+        安全加载数据到TiDB,包含以下优化:
+        1. 分批处理避免内存溢出
+        2. 完善的连接管理
+        3. 错误处理和重试机制
+        """
+        total_rows = len(df)
+        success_rows = 0
+        engine = self.get_engine()
+        for i in range(0, total_rows, batch_size):
+            batch = df.iloc[i:i + batch_size]
+            retry_count = 0
+            max_retries = 4
+
+            while retry_count < max_retries:
+                try:
+                    with tempfile.NamedTemporaryFile(mode='w') as tmp:
+                        batch.to_csv(tmp, index=False, header=False, sep='\t')
+                        tmp.flush()
+
+                        with engine.begin() as conn:  # 自动提交事务
+                            # 设置当前会话内存配额
+                            conn.execute(text("SET tidb_mem_quota_query = 2147483648"))  # 2GB
+
+                            # 执行LOAD DATA
+                            conn.execute(text(f"""
+                                LOAD DATA LOCAL INFILE '{tmp.name}' 
+                                INTO TABLE {table_name} 
+                                FIELDS TERMINATED BY '\t'
+                                LINES TERMINATED BY '\n'
+                            """))
+
+                        success_rows += len(batch)
+                        logger.info(f"成功加载批次 {i // batch_size + 1}: {len(batch)} 行")
+                        break  # 成功则跳出重试循环
+
+                except Exception as e:
+                    retry_count += 1
+                    logger.info(f"批次 {i // batch_size + 1} 第 {retry_count} 次尝试失败: {str(e)}")
+                    if retry_count >= max_retries:
+                        logger.error(f"批次 {i // batch_size + 1} 达到最大重试次数")
+                        logger.error(traceback.format_exc())
+                        raise
+                    time.sleep(2 ** retry_count)  # 指数退避
+
+        logger.info(f"数据加载完成: 总计 {success_rows}/{total_rows} 行")
+        return success_rows

+ 3 - 0
utils/db/__init__.py

@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/6/7
+# @Author  : 魏志亮

+ 3 - 0
utils/log/__init__.py

@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/5/16
+# @Author  : 魏志亮

+ 38 - 0
utils/log/trans_log.py

@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# @Time    : 2024/5/16
+# @Author  : 魏志亮
+
+import datetime
+import logging
+import sys
+from os import path, sep, makedirs
+
+from utils.conf.read_conf import read_conf, yaml_conf
+
+logger = logging.getLogger("energy_online_data")
+logger.setLevel(logging.INFO)
+stout_handle = logging.StreamHandler(sys.stdout)
+stout_handle.setFormatter(
+    logging.Formatter("%(asctime)s: %(message)s"))
+stout_handle.setLevel(logging.INFO)
+logger.addHandler(stout_handle)
+
+config_path = path.abspath(__file__).split("utils")[0] + 'conf' + sep + 'config.yaml'
+config = yaml_conf(config_path)
+log_path_dir = read_conf(config, 'log_path_dir', "/data/logs")
+
+log_path = log_path_dir + sep + r'energy_online_data'
+file_path = path.join(log_path)
+
+if not path.exists(file_path):
+    makedirs(file_path, exist_ok=True)
+file_name = str(file_path + sep + str(datetime.date.today()) + '.log')
+
+file_handler = logging.FileHandler(file_name, encoding='utf-8')
+file_handler.setFormatter(
+    logging.Formatter("%(asctime)s: %(message)s"))
+file_handler.setLevel(logging.INFO)
+logger.addHandler(file_handler)
+
+# def logger.info(*args):
+#     logger.info("  ".join([str(a) for a in args]))

+ 0 - 0
utils/systeminfo/__init__.py


+ 90 - 0
utils/systeminfo/sysinfo.py

@@ -0,0 +1,90 @@
+from os import *
+
+import psutil
+
+from utils.log.trans_log import logger
+
+
+def print_memory_usage(detail=""):
+    # 获取当前进程ID
+    pid = getpid()
+    # 获取进程信息
+    py = psutil.Process(pid)
+    # 获取内存信息
+    memory_info = py.memory_info()
+    # RSS (Resident Set Size) 是进程实际占用的物理内存大小
+    memory_usage_rss = memory_info.rss
+    # VMS (Virtual Memory Size) 是进程使用的虚拟内存大小
+    memory_usage_vms = memory_info.vms
+
+    # 将字节转换为更易读的单位
+    memory_usage_rss_mb = memory_usage_rss / (1024 ** 2)
+    memory_usage_vms_mb = memory_usage_vms / (1024 ** 2)
+
+    logger.info(f"{detail},Memory usage (RSS): {memory_usage_rss_mb:.2f} MB")
+    logger.info(f"{detail},Memory usage (VMS): {memory_usage_vms_mb:.2f} MB")
+
+
+def get_cpu_count():
+    return psutil.cpu_count()
+
+
+def get_available_cpu_count_with_percent(percent: float = 1):
+    cpu_count = get_cpu_count()
+    return int(cpu_count * percent)
+
+
+def get_file_size(file_path):
+    return path.getsize(file_path)
+
+
+def get_dir_size(dir_path):
+    return sum(get_file_size(path.join(dir_path, file)) for file in listdir(dir_path) if
+               path.isfile(path.join(dir_path, file)))
+
+
+def get_available_memory_with_percent(percent: float = 1):
+    memory_info = psutil.virtual_memory()
+    return int(memory_info.available * percent)
+
+
+def get_max_file_size(file_paths: list[str]):
+    max_size = 0
+    for file_path in file_paths:
+        file_size = get_file_size(file_path)
+        if file_size > max_size:
+            max_size = file_size
+    return max_size
+
+
+def use_files_get_max_cpu_count(file_paths: list[str], memory_percent: float = 1 / 12, cpu_percent: float = 2 / 5):
+    max_file_size = get_max_file_size(file_paths)
+    free_memory = get_available_memory_with_percent(memory_percent)
+    count = int(free_memory / max_file_size)
+    max_cpu_count = get_available_cpu_count_with_percent(cpu_percent)
+    result = count if count <= max_cpu_count else max_cpu_count
+    if result == 0:
+        result = 1
+
+    if result > len(file_paths):
+        result = len(file_paths)
+
+    logger.info(f"总文件数:{len(file_paths)},获取最大文件大小:{str(round(max_file_size / 2 ** 20, 2))}M"
+                f"可用内存:{str(get_available_memory_with_percent(1) / 2 ** 20)}M"
+                f"总CPU数:{get_cpu_count()}CPU使用比例:{round(cpu_percent, 2)}"
+                f"CPU可用数量:{max_cpu_count},最终确定使用进程数:{result}")
+    return result
+
+
+def max_file_size_get_max_cpu_count(max_file_size, memory_percent: float = 1 / 6, cpu_percent: float = 2 / 5):
+    free_memory = get_available_memory_with_percent(memory_percent)
+    count = int(free_memory / max_file_size)
+    max_cpu_count = get_available_cpu_count_with_percent(cpu_percent)
+    result = count if count <= max_cpu_count else max_cpu_count
+    if result == 0:
+        result = 1
+    logger.info(f"获取最大文件大小:{str(round(max_file_size / 2 ** 20, 2))}M"
+                f"可用内存:{str(get_available_memory_with_percent(1) / 2 ** 20)}M"
+                f"总CPU数:{get_cpu_count()}CPU使用比例:{round(cpu_percent, 2)}"
+                f"CPU可用数量:{max_cpu_count},最终确定使用进程数:{result}")
+    return result