Smart_Report/Self_defined_functions.py
2025-04-17 14:15:10 +08:00

430 lines
23 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Ziran Gao 20240905
# 智能二次运维项目中,自定义函数合集
#-------------2024年10月11日--------------------------------------------------------------------------------------------------------
#增加存入定值至定值数据库
#重写从excel中读数据功能。这里面那个暂时没用。
#-------------2024年9月13日--------------------------------------------------------------------------------------------------------
#增加连接至变位数据库,数据库平台调试未完成
#增加从excel中读取基础参数功能
#-------------2024年9月5日--------------------------------------------------------------------------------------------------------
# 增加连接至主数据库函数注意只可连接至ISMS_BASE数据库。
# encoding:utf-8
#------------------主数据库连接函数--------------------------------------------------------------------------------------------------
import pymssql
import pandas as pd
import redis
import msgpack
import warnings
import math
def connectMainDatabase():
try:
conn = pymssql.connect(host='127.0.0.1', #IP地址按需更改
user='sa', #数据库用户名,按需更改
password='sa', #数据库密码,按需更改
database='ISMS_BASE', #连接数据库名称,按需更改
charset='utf8',
tds_version=r'7.0') #重要pymssql中需声明tds版本勿轻易升级pymssql包如升级请查阅对应TDS版本并修改否则会报错。
print("连接成功")
except pymssql.Error as e:
print("连接失败"+str(e))
return conn
#---------------------------------------------------------------------------------------------------------------------------------\
#------------------变位遥信数据库连接函数--------------------------------------------------------------------------------------------------
#import pymssql
def connectDataDatabase():
try:
conn = pymssql.connect(host='127.0.0.1', #IP地址按需更改
user='sa', #数据库用户名,按需更改
password='sa', #数据库密码,按需更改
database='ISMS_DATA', #连接数据库名称,按需更改
charset='utf8',
tds_version=r'7.0') #重要pymssql中需声明tds版本勿轻易升级pymssql包如升级请查阅对应TDS版本并修改否则会报错。
print("连接成功")
except pymssql.Error as e:
print("连接失败"+str(e))
return conn
#---------------------------------------------------------------------------------------------------------------------------------
#------------------从Excel中读参数函数当前没用--------------------------------------------------------------------------------------------------
# 输入 PwrSuplyWay是字符串表示sheet的名字没有这个名字会报错islarge表示是大所还是小所1是大所2是小所
# EXCEL格式需用sheet表示供电模式供电模式的名称应与设定一致不需要表头变量名字勿随意修改。有一个大所文件和一个小所文件分别用于展示不同的数据。
def ImportExcelParameter(PwrSuplyWay, islarge):
if islarge == 1: #变电所
ImportedParameter = pd.read_excel('变电所定值整定基础参数表.xlsx',sheet_name=PwrSuplyWay,header=None)
ImportedParameter_dict = ImportedParameter.set_index(0)[1].to_dict()
elif islarge == 2: #分区所
df = pd.read_excel('分区所定值整定基础参数表.xlsx',sheet_name=PwrSuplyWay,header=None)
ImportedParameter_dict = ImportedParameter.set_index(0)[1].to_dict()
else:
raise ValueError(f"Invalid value for 'islarge': {islarge}. Expected 1 for 变电所 or 2 for 分区所.")
return(ImportedParameter_dict)
#--------------------------------------------------------------------------------------------------------------------------------------------------
#------------------------------------检查输入是否是可计算的量-----------------------------------------------------------------------------------------
# 如果输入是int/float/complex即可正常工作否则报错。
def check_input(value):
if not isinstance(value, (int, float, complex)):
raise ValueError(f"输入的值 '{value}' 不是一个可运算的数字类型")
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------将计算出的定值存进对应数据库--------------------------------------------------------------------
# 输入数据库名字和定值词典变量。
# 当前数据库包括馈线0区数据库馈线1区数据库馈线2区数据库AT数据库并补数据库主变数据库
def SavePresetValuetoSQLSERVER(table_name,mydict):
import pymssql #在python中编辑SQL SERVER数据库
#import Self_defined_functions #引入自定义函数文件
conn = connectMainDatabase() #连接至ISMS_BASE数据库
cursor = conn.cursor() #获取pymssql提供的SQL Server编辑游标
sql_truncate = f"TRUNCATE TABLE {table_name}" #把原有表格清空
sql_insert = f"INSERT INTO {table_name} (PresetValueName, Value) VALUES (%s, %d)" #把新定值存入
cursor.execute(sql_truncate) #执行清空语句
conn.commit()
# 遍历字典并插入每个定值
for preset_name, preset_value in mydict.items(): #执行存入语句
cursor.execute(sql_insert, (preset_name, preset_value))
# 提交更改并关闭连接
conn.commit() # 提交事务,确保更改生效
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------将读取到的遥测量对应数据库im_Obtained_YC--------------------------------------------------------------------
def obtainYC():
redis_host = "192.168.110.229" # 替换为实际的主机名或 IP
redis_port = 36379 # 替换为实际的端口
redis_password = "yunda123" # 替换为实际的密码
# 使用 redis-py 配置 Redis 连接
client = redis.Redis(
host=redis_host,
port=redis_port,
db=0, # 指定默认数据库为 0
password=redis_password,
socket_timeout=20, # 等价于 ConnectTimeout
socket_connect_timeout=20 # 等价于 SyncTimeout
)
# 测试连接和数据操作
try:
client.ping()
print("Successfully connected to Redis!")
# 示例操作:设置和获取一个键
client.set("your_key", "your_value")
value = client.get("your_key")
data = client.hgetall("telemeteringModelList_Zongzi") # 使用 HashSet 的键 遥测
if data:
conn = connectMainDatabase() #连接至ISMS_BASE数据库
cursor = conn.cursor() #获取pymssql提供的SQL Server编辑游标
sql_truncate = f"TRUNCATE TABLE im_Obtained_YC;" #把原有表格清空
cursor.execute(sql_truncate) #执行清空语句
conn.commit()
# 遍历并解码每个字段
decoded_data = {}
for key, value in data.items():
# 值都使用 MessagePack 序列化
#print(key)
decoded_value_YC = msgpack.unpackb(value)
#print(decoded_value_YC)
sql_insert = f"INSERT INTO im_Obtained_YC (PresetValueName, Value, Unit, ismsBaseYCId, EquipmentinfoID, LastValue, PresetValueID) VALUES (%s, %d, %s, %s, %s, %d, %s)"
#print(decoded_value_YC.items())
cursor.execute(sql_insert, (decoded_value_YC['Name'], decoded_value_YC['ResultValue'], decoded_value_YC['Unit'], decoded_value_YC['ismsbaseYCId'], decoded_value_YC['EquipmentInfoId'], decoded_value_YC['LastResultValue'], decoded_value_YC['Id']))
conn.commit()
#Self_defined_functions.SaveObtainedYCtoSQLSERVER(cursor,decoded_value_YC)
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
except redis.ConnectionError as e:
print(f"Redis connection error: {e}")
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------将读取到的遥测量按装置整理归类--------------------------------------------------------------------
def obtainYC_Device():
redis_host = "192.168.110.229" # 替换为实际的主机名或 IP
redis_port = 36379 # 替换为实际的端口
redis_password = "yunda123" # 替换为实际的密码
# 使用 redis-py 配置 Redis 连接
client = redis.Redis(
host=redis_host,
port=redis_port,
db=0, # 指定默认数据库为 0
password=redis_password,
socket_timeout=20, # 等价于 ConnectTimeout
socket_connect_timeout=20 # 等价于 SyncTimeout
)
# 测试连接和数据操作
try:
client.ping()
print("Successfully connected to Redis!")
# 示例操作:设置和获取一个键
client.set("your_key", "your_value")
value = client.get("your_key")
data = client.hgetall("telemeteringModelList_Zongzi") # 使用 HashSet 的键 遥测
#print(data)
if data:
conn = connectMainDatabase() #连接至ISMS_BASE数据库
cursor = conn.cursor() #获取pymssql提供的SQL Server编辑游标
YC_List_Dist = {}
YC_List_Prtct = {}
YC_List_MnTrns = {}
for key, value in data.items():
decoded_value_YC = msgpack.unpackb(value)
#print(decoded_value_YC)
sql_find = f"SELECT * FROM im_DeviceData WHERE ID = '{decoded_value_YC['ismsbaseYCId']}'"
cursor.execute(sql_find)
Devicelist = cursor.fetchall()
#rint(Devicelist)
if Devicelist != []:
DeviceID = Devicelist[0][1]
sql_find_1 = f"SELECT * FROM im_ProtectDevice_new WHERE DeviceID = '{DeviceID}'"
cursor.execute(sql_find_1)
Devicetype_1 = cursor.fetchall()
Devicetype = Devicetype_1[0][2].encode('latin1').decode('gbk')
if Devicetype.find('馈线保护测控装置') != -1:#把4.0排除在外了,以后很可能得改。:
if YC_List_Prtct.get(Devicetype) == None:
YC_List_Prtct[Devicetype] = {}
YC_List_Prtct[Devicetype][decoded_value_YC['Name']] = decoded_value_YC['ResultValue']
if Devicetype.find('故障测距装置') != -1:
if YC_List_Dist.get(Devicetype) == None:
YC_List_Dist[Devicetype] = {}
YC_List_Dist[Devicetype][decoded_value_YC['Name']] = decoded_value_YC['ResultValue']
if Devicetype.find('主变测控装置') != -1:
if YC_List_MnTrns.get(Devicetype) == None:
YC_List_MnTrns[Devicetype] = {}
YC_List_MnTrns[Devicetype][decoded_value_YC['Name']] = decoded_value_YC['ResultValue']
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
except redis.ConnectionError as e:
print(f"Redis connection error: {e}")
return YC_List_MnTrns, YC_List_Prtct,YC_List_Dist
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------将读取到的遥信量对应数据库im_Obtained_YX--------------------------------------------------------------------
def obtainYX():
redis_host = "192.168.110.229" # 替换为实际的主机名或 IP
redis_port = 36379 # 替换为实际的端口
redis_password = "yunda123" # 替换为实际的密码
# 使用 redis-py 配置 Redis 连接
client = redis.Redis(
host=redis_host,
port=redis_port,
db=0, # 指定默认数据库为 0
password=redis_password,
socket_timeout=20, # 等价于 ConnectTimeout
socket_connect_timeout=20 # 等价于 SyncTimeout
)
# 测试连接和数据操作
try:
client.ping()
print("Successfully connected to Redis!")
# 示例操作:设置和获取一个键
client.set("your_key", "your_value")
value = client.get("your_key")
data = client.hgetall("telesignalisationModelList_Zongzi") # 使用 HashSet 的键 遥测
if data:
conn = connectMainDatabase() #连接至ISMS_BASE数据库
cursor = conn.cursor() #获取pymssql提供的SQL Server编辑游标
sql_truncate = f"TRUNCATE TABLE im_Obtained_YX;" #把原有表格清空
cursor.execute(sql_truncate) #执行清空语句
conn.commit()
# 遍历并解码每个字段
decoded_data = {}
for key, value in data.items():
# 值都使用 MessagePack 序列化
#print(key)
decoded_value_YX = msgpack.unpackb(value)
#print(decoded_value_YC)
sql_insert = f"INSERT INTO im_Obtained_YX (PresetValueName, Value, YesValue, ismsBaseYXId, EquipmentinfoID, NoValue, PresetValueID) VALUES (%s, %d, %s, %s, %s, %d, %s)"
#print(decoded_value_YC.items())
cursor.execute(sql_insert, (decoded_value_YX['Name'], decoded_value_YX['ResultValue'], decoded_value_YX['YesContent'], decoded_value_YX['ismsbaseYXId'], decoded_value_YX['EquipmentInfoId'], decoded_value_YX['NoContent'], decoded_value_YX['Id']))
conn.commit()
#Self_defined_functions.SaveObtainedYCtoSQLSERVER(cursor,decoded_value_YC)
#print(decoded_value_YX)
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
except redis.ConnectionError as e:
print(f"Redis connection error: {e}")
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------将读取到的定值量存进对应数据库im_Obtained_SysValue和im_Obtained_UsrValue--------------------------------------------------------------------
def obtainPresetValue():#这直接拉所有装置的定值,后面可能再加一个分开拉某一装置的吧
redis_host = "192.168.110.229" # 替换为实际的主机名或 IP
redis_port = 36379 # 替换为实际的端口
redis_password = "yunda123" # 替换为实际的密码
conn = connectMainDatabase() #连接至ISMS_BASE数据库
cursor = conn.cursor() #获取pymssql提供的SQL Server编辑游标
sql_truncate = f"TRUNCATE TABLE im_Obtained_SysValue;" #把原有表格清空
cursor.execute(sql_truncate) #执行清空语句
conn.commit()
sql_truncate = f"TRUNCATE TABLE im_Obtained_UsrValue;" #把原有表格清空
cursor.execute(sql_truncate) #执行清空语句
conn.commit()
# 使用 redis-py 配置 Redis 连接
client = redis.Redis(
host=redis_host,
port=redis_port,
db=0, # 指定默认数据库为 0
password=redis_password,
socket_timeout=20, # 等价于 ConnectTimeout
socket_connect_timeout=20 # 等价于 SyncTimeout
)
# 测试连接和数据操作
try:
client.ping()
print("Successfully connected to Redis!")
# 获取所有键
all_keys = client.keys('*')
# 筛选出前缀为 DZ_ 的键
dz_keys = [key for key in all_keys if key.decode('utf-8').startswith('DZ_')]
# 打印筛选后的键
for key in dz_keys:
#print(key.decode('utf-8'))
address = key.decode('utf-8').split('_')[2]
if address == 'System':
client.set("your_key", "your_value")
value = client.get("your_key")
data = client.hgetall(key)
#print(data)
for key, value in data.items():
# 值都使用 MessagePack 序列化
#print(key)
decoded_value_Pre_sys = msgpack.unpackb(value)
#print(decoded_value_Pre_sys)
#print(decoded_value_YC)
sql_insert = f"INSERT INTO im_Obtained_SysValue (PresetValueName, Value, ID, DeviceID) VALUES (%s, %d, %s, %s)"
#print(decoded_value_YC.items())
cursor.execute(sql_insert, (decoded_value_Pre_sys['DzComment'], decoded_value_Pre_sys['Value'], decoded_value_Pre_sys['Id'], decoded_value_Pre_sys['DeviceId']))
conn.commit()
#Self_defined_functions.SaveObtainedYCtoSQLSERVER(cursor,decoded_value_YC)
if address == 'User':
client.set("your_key", "your_value")
value = client.get("your_key")
data = client.hgetall(key)
for key, value in data.items():
# 值都使用 MessagePack 序列化
#print(key)
decoded_value_Pre_Usr = msgpack.unpackb(value)
#print(decoded_value_Pre_Usr)
sql_insert = f"INSERT INTO im_Obtained_UsrValue (PresetValueName, Value, ID, DeviceID) VALUES (%s, %d, %s, %s)"
#print(decoded_value_YC.items())
cursor.execute(sql_insert, (decoded_value_Pre_Usr['DzComment'], decoded_value_Pre_Usr['Value'], decoded_value_Pre_Usr['Id'], decoded_value_Pre_Usr['DeviceId']))
conn.commit()
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
except redis.ConnectionError as e:
print(f"Redis connection error: {e}")
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------定值校验-读取装置定值--------------------------------------------------------------------
def getdevicePresetValue(device):
conn = connectMainDatabase()#获取当前装置的所有定值
cursor = conn.cursor() #获取pymssql提供的SQL Server编辑游标
sql_read_Usr = f"SELECT * FROM im_Obtained_UsrValue WHERE deviceID = '" + device + "';"
#print(sql_read_Usr)
cursor.execute(sql_read_Usr)
results_Usr = cursor.fetchall()
Preset_dict = {}
for row in results_Usr:
Preset_dict.update({row[1].encode('latin1').decode('gbk'):row[2]})
results_Usr_dict = {row[0]: row[1:] for row in results_Usr}
sql_read_Sys = f"SELECT * FROM im_Obtained_SysValue WHERE deviceID = '" + device + "';"
cursor.execute(sql_read_Sys)
results_Sys = cursor.fetchall()
results_Sys_dict = {row[0]: row[1:] for row in results_Sys}
for row in results_Sys:
Preset_dict.update({row[1].encode('latin1').decode('gbk'):row[2]})
sql_read_devicetype = f"SELECT * FROM im_ProtectDevice_new WHERE deviceID = '" + device + "';"
cursor.execute(sql_read_devicetype)
results_devicetype = cursor.fetchall()
type_flag = results_devicetype[0][2].encode('latin1').decode('gbk')
if type_flag.find('主变保护')!=-1:
device_type_flag = 1
if type_flag.find('馈线')!=-1:
device_type_flag = 2
if type_flag.find('自耦变')!=-1:
device_type_flag = 3
if type_flag.find('并联补偿')!=-1:
device_type_flag = 4
if type_flag.find('测距')!=-1:
device_type_flag = 5
if type_flag.find('动力变')!=-1:
device_type_flag = 5
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
return Preset_dict,device_type_flag
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------定值校验-定值合格/不合格--------------------------------------------------------------------
def checkPresetFlag(PresetName,PresetResult,checked_preset,checked_fail_reason,FailReason='',):
if PresetResult == 1:#通过
if PresetName in checked_preset and checked_preset[PresetName] == '校验不通过':
pass
else:
checked_preset[PresetName] = '校验通过'
else:#不通过
if PresetName in checked_fail_reason:
checked_preset[PresetName] = '校验不通过'
checked_fail_reason[PresetName] = checked_fail_reason[PresetName] + FailReason
else:
checked_preset[PresetName] = '校验不通过'
checked_fail_reason[PresetName] = FailReason
return checked_preset,checked_fail_reason
#---------------------------------------------------------------------------------------------------------------------------------
#-----------------------------------定值校验用,第一个判断是否是连续自然数,第二个判断是否递增,第三个判断字典里是不是所有值相等,第四个比较校验值相对误差-------------------------------------------------------------------
def is_continuous(lst):
for i in range(1, len(lst)):
if lst[i] - lst[i - 1]!= 1:
return False
return True
def is_increasing(dictionary):
values = list(dictionary.values())
for i in range(1, len(values)):
if values[i] <= values[i - 1]:
return False
return True
def are_all_values_equal(dictionary):
if not dictionary:
return True # 空字典视为所有值相等
first_value = next(iter(dictionary.values())) # 获取第一个值作为基准
return all(value == first_value for value in dictionary.values())
def are_values_equal_with_tolerance(a, b ,tol = 0.05):
if a == 0 or b == 0:
return abs(a - b) < 0.001 # 使用绝对误差比较
else:
return abs(a - b) / max(abs(a), abs(b)) < tol
def vector_add(A_magnitude, A_angle_deg, B_magnitude, B_angle_deg):
# 将角度转换为弧度
A_angle_rad = math.radians(A_angle_deg)
B_angle_rad = math.radians(B_angle_deg)
# 将矢量转换为坐标表示
A_x = A_magnitude * math.cos(A_angle_rad)
A_y = A_magnitude * math.sin(A_angle_rad)
B_x = B_magnitude * math.cos(B_angle_rad)
B_y = B_magnitude * math.sin(B_angle_rad)
# 向量加法
sum_x = A_x + B_x
sum_y = A_y + B_y
# 计算和矢量的模长和角度
sum_magnitude = math.hypot(sum_x, sum_y)
sum_angle_rad = math.atan2(sum_y, sum_x)
sum_angle_deg = math.degrees(sum_angle_rad)
return(sum_magnitude,sum_angle_deg,sum_angle_rad)