博图V19的DB块,批量导入组态王

最近在使用组态王做一个厂区的DCS项目,plc选用西门子1500系列。一共用了3个1500,5个io站点。整个项目下来,点位大约有5000多个。把这5000多个点位,一个一个导入到组态王,无疑是一个非常非常非常难受的工作,不仅无聊,而且很容易出错。

一、首先,解释一下DB块。DB块是西门子S7系列的PLC,一个非常有特色的功能。大致功能就说允许用户自己定义一个内存区域,如DB1,DB2,DB3.....DB100,等等,每个DB块,可以由用户自定义一些变量或者结构体。

试想一下,当一个PLC控制了好几条产线,如果都把这写变量,全部写到一块,维护起来就比较麻烦,当然写到一块也不是不可以。按车间或者产线,分别写到不同的DB块上,维护起来更方便。下图是博图V19导出的一个DB块内容,PDF文件。可以看到里面DB块基本信息,和结构体定义。

一般情况下, 对同类型的设备控制,比如皮带,风机,等。会使用相同的结构体进行定义,如下图。

 1A-CVS01和1A-CBC02。这两个设备,都是一类型的设备(说白了电机控制都一样),所以两个设备用了相同的结构体定义,不同的是,设备名字不一样,以及结构体内部各个属性对应的内存地质不一样。

他们的控制方式,就是PLC编程是一样的。同时在DCS,就是组态王画面里面,两个设备控制方式也是一样的。这两个结构体怎么才能在DCS画面控制呢?答案就是给这两个结构体在组态王变量里面也定义一下。

二、接下来就是在组态王定义结构体和变量,因为这两个结构体结构一样,所以,只需要在组态王定义一个结构类型。定义两个变量。

结构体定义按下图的步骤。

结构定义完以后,就是定义变量的步骤,先点左侧的变量,再点新建。如下图。变量包含了若干个属性,见下面属性下拉框。每个属性,都需要定义一所在的plc和地址。完整DB5.62.0。表示,DB块5,里面的第62个字节的,第0位。最后一个只有bit类型需要,如果是int,real不需要。

通常情况下,一个厂区,几百个电机到上千个电机,任何设备要运转,都需要电机嘛。当然也不都是同一类型的设备,也会有变频电机,软起电机,也有可以正反转的电机等等,不同的设备类型,控制肯定不一样,那么结构体定义也就不一样。

所以通常一个厂区的控制系统会包含若干个PLC,若干个DB块,十几个结构体定义,成百上千个结构体变量。几千个基本变量。如下图,其中一个DB块已经定义到了3600个字节了,假设一个结构体20个字节,也就是180个结构体定义。1000多个变量定义了。

要给这些变量,一个一个手动编辑到组态王,确实是一个非常庞大的工程,耗时耗力,还非容易出错。所以决定做一个脚本,来简化变量(点位)导入。上一篇写了一个简单的DB块导入功能,见链接DCS项目调试踩坑记录_dcs调试记录表-CSDN博客

这个文章里比较简单,适合单个DB块,并且结构体都是固定死的。并不适合多个DB块,结构体不一样的情况。

三:DB块的pdf直接生成组态王的DB文件。整个过程分为两步,第一步,解析所有pdf文件,循环所有结构体定义,提取出其中不同的结构体定义。就是全部读取,然后给结构相同的去掉。然后给结构体定义文件保存为data.json。如下图。这个文件里面包含所有结构体定义,类型,plc里面变量名称,以及组态王里面变量名称。当然这一步也可以由开发人员自己定义,直接按下面格式编写就行。不过建议先用脚本跑一下,生成基本结构,然后开发人员再根据个人喜欢优化一下

第二步,读取所有的pdf文件,以及上一步定义的结构文件,循环所有pdf,所有结构体和所有变量。根据上一步定义的结构体自动生成组态王DB文件的结构体定义,如下图,模板页和模板定义页。

然后,把所有结构体变量,按规则生成组态王结构变量,如下图:

最终生成完成以后,会生成一个test.xls文件。组态王工程管理页面,点击导入,即可完成所有变量导入。见下图:

四:代码分享。解析结构体代码如下

import pdfplumber
import os
import json
path='./'arr=[]  #存储结构体的数组#plc变量名称和组态王变量名称的映射关系,如果不定义这个,会直接使用plc里面的变量名称
varNames={'iinf':'状态字','balm':'报警','disysj':'运行时长','rdianliu_fankui':'电流','rpinlv_fankui':'频率','bstate_run_fw':'正向运行','bstate_run_bw':'反向运行','bstate_fault':'故障','bstate_ready':'备妥','fengjiyunxing':'风机运行','chuchenqirukouyali':'入口压力','panglu':'旁路运行','rm1dianliu_fankui':'M1电流','rm2dianliu_fankui':'M2电流','rrt_pos':'开度','fankuizhuansu':'转速','bstate_open_done':'开到位','bstate_close_done':'关到位','zhengxiangxianwei':'正限位','fanxingxianwei':'负限位','bstate_runz':'正向运行','bstate_runf':'反向运行','bstopallowed':'停止许可','bstart':'启动','bstop':'停止','startallowed':'启动许可','stopallowed':'停止许可','rpinlv_geiding':'手动频率','rpinlv_geiding_a':'自动频率','ma':'模式','breset':'复位','em':'急停','bopen':'手动开','bclose':'手动关','bstop':'手动停','bopen_a':'自动开','bclose_a':'自动关','bstop_a':'自动停','zhengxiangqidong':'正向启动','fanxiangqidong':'反向启动','tingzhi':'停止','bstartz':'正向启动','bstartf':'反向启动','bstartzallowed':'正向启动许可','bstartfallowed':'反向启动许可','wendu1':'温度1','wendu2':'温度2','wendu3':'温度3'}
#有时候plc定义变量名称会敲错,这个功能是给敲错的单词转换一下,例如chukou拼写成cukou,这里定义一下'cukou':'chukou'
wordTrans={'chuchanqirukouyali':'chuchenqirukouyali','zhaunsufankui':'fankuizhuansu','zhuansufankui':'fankuizhuansu','bstate_ready_1':'bstate_ready','bstate_fault_1':'bstate_fault'} #有些拼错的,使用这个转换一下#获取变量在组态王的名称
def getVarName(s):if s in varNames.keys():return varNames[s]return s
#转换名称
def transName(nm):if nm in wordTrans.keys():print(nm+" ===== " +wordTrans[nm])return wordTrans[nm]return nm#读取pdf里面的db块号
def getDBNum(pdf):                                  #解析DB块号tb=pdf.pages[0].extract_tables()[1]             #获取第一页name=tb[2][1]                                   #DB块注释dbNum=tb[2][3]                                  #DB块号print(name,dbNum)return 'DB' +dbNum#比较两个结构体是否一样
#a1是数组,a2是map
def compStruct(a1,a2) :for nm in a1:if nm not in a2.keys(): return Falsereturn True#检查是否有重复的结构体,如果没有就增加上去
def checkStruct(s):#print('check struct',s)if s=={} :return #无效的结构体f = Falsel1=len(s['attrs'])for o in arr:l2= len ( o['attrs'].keys() )if l2!=l1 : continue                #属性数量不一样,直接跳过f=compStruct(s['attrs'],o['attrs'])if f == True: return                #找到一样的,不用再找了if f==False :arr.append(s)return
#----------------------------------------------------------------------------------------------------
def formatStr(s):s1=s.replace(' ','').replace('\r','').replace('\n','').lower()#print(s,s1)return s1
#读取pdf,并解析
def readPDF(fname):if fname.find('.pdf')==-1 :returnpdf=pdfplumber.open(fname)DB=getDBNum(pdf)print("dbname",DB)plc=fname.split('_')[0]mode='只读'                                     #默认读写模式if fname.find("write") !=-1:mode='只写'                                 #只写ss={}                                           #临时结构体for pg in pdf.pages:                            #循环所有页data =pg.extract_table()                    #获取表格for r in data :                             #循环所有行#print(r)name=transName(formatStr(r[0]))                    #名称type=formatStr(r[1])                              #类型add=formatStr(r[2])                               #地址remark=formatStr(r[13])                            #备注信息# print(name,type,remark)if  name=='名称' or name=='w' or name.find('备用')!=-1:            #跳过无用的行#print('skip  '+name)continue#print(name,type)if type == 'struct' :                   #如果是Struct ,可能是结构体开头checkStruct(ss)                     #添加到结构体if name.find('static') ==-1:ss={'name':remark,'DB':DB,'mode':mode,'attrs':{},'plc':plc}else:ss={}                           #无效的结构体,直接跳过continue                            #结构体开头行if name.find('static')==-1 and 'attrs' in ss.keys():                    #如果是一般列,并且有属性ss['attrs'][name]={'type':type,'add':add,'name':getVarName(name)}    #添加到属性集合,var是组态王里面的名称
#-----------------------------------------------------------------------------------------------------------------------------------# 遍历当前目录
for file_name in os.listdir(path):# 处理目录中的文件或子目录full_path = os.path.join(path, file_name)  # 拼接文件或子目录的完整路径if os.path.isfile(full_path):  # 判断是否为文件print("文件:", file_name)readPDF(file_name)elif os.path.isdir(full_path):  # 判断是否为子目录print("子目录:", file_name)
print('------------------------------------------------------------')
print(arr)# 打开文件
with open("data.json", "w",encoding="utf-8") as file:# 使用json.dump将数据写入文件json.dump(arr, file,ensure_ascii=False)

生成组态王DB文件代码如下:

import pdfplumber
import os
import json
from openpyxl import Workbook   #用于写入excel,如果没有需要pip install openpyxl
from openpyxl import load_workbook#创建组态王结构体声明    
def createStruct(dat):print("data length ",len(dat))startId=1                                                           #默认从编号1开始st1 = wb.create_sheet("模板页")                                         #结构体变量模板st2 = wb.create_sheet("模板定义页")st1.append(['说明:本页为数据词典中所有模板定义  请不要编辑此行'])varId=21                                                      #变量id,21开始for o in dat:#print(o)st1.append(['[模板]','模板ID','模板名称','模板使用记数','注释'])    #结构体行st1.append(['',startId,o['name'],-2,''])                               #结构体名称st1.append(['','[成员]',	'成员ID','成员名称','成员类型'])         #结构体开始id=1                                                                #属性开始startId=startId+1for k in o['attrs'].keys() :o['attrs'][k]['varid']=varId       tp=o['attrs'][k]['type']                                  #变量idvarId=varId+1                                               #增加一个st1.append(['','',id,o['attrs'][k]['name'],types[tp]])id=id+1###下面是输出模板定义地方st2.append(['说明:本页为数据词典中所有基本变量  请不要编辑此行'])st2.append(['[内存整型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','是否保存值','是否保存参数','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])#st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','是否保存值','是否保存参数','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])st2.append([])st2.append(['[内存实型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','是否保存值','是否保存参数','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])st2.append([])st2.append(['[内存离散]'])st2.append(['变量ID','变量名','变量使用记数','初始值','是否保存值','是否保存参数','报警组','优先级','是否产生报警','报警类型(开/关/变位)','关报警文本','开报警文本','开到关报警文本','关到开报警文本','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])st2.append([])st2.append(['[内存字符串]'])st2.append(['变量ID','变量名','变量使用记数','初始字符串(<127字节)','是否保存值','是否保存参数','安全区','注释','变量签名属性'])st2.append([])st2.append(['[IO整型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','最小原始值','最大原始值','是否保存值','是否保存参数','设备名','寄存器名称','数据类型','读写属性','采集频率(毫秒)','转换方式','高级转换方式','线性表名称','最小累计值','最大累计值','是否允许DDE访问','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录/每次采集记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])for o in dat:print(o)sname=o['name']db=o['DB']+"."for k in o['attrs'].keys():tp=o['attrs'][k]['type']if tp=='dint' :name=o['attrs'][k]['name']id=o['attrs'][k]['varid']add=o['attrs'][k]['add'].split('.')[0]add=db+addst2.append([id,sname+"."+name,-2,0,0,-10000,999999999,-1000,999999999,'否','否',o['plc'],add,'LONG',o['mode'],1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无','','',144])# st2.append([id,	sname+"."+name,0,0,0,-10000,999999999,-10000,999999999,'否','否',o['plc'],add,'LONG',o['mode'],1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无','',144,''])if tp=='int' :name=o['attrs'][k]['name']id=o['attrs'][k]['varid']add=o['attrs'][k]['add'].split('.')[0]add=db+addst2.append([id,sname+"."+name,-2,0,0,-10000,999999999,-1000,999999999,'否','否',o['plc'],add,'SHORT',o['mode'],1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无','','',144])#st2.append([id,	sname+"."+name,0,0,0,-10000,999999999,-10000,999999999,'否','否',o['plc'],add,'SHORT',o['mode'],1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无','',144,''])st2.append([])st2.append(['[IO实型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','最小原始值','最大原始值','是否保存值','是否保存参数','设备名','寄存器名称','数据类型','读写属性','采集频率(毫秒)','转换方式','高级转换方式','线性表名称','最小累计值','最大累计值','是否允许DDE访问','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录/每次采集记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])for o in dat:sname=o['name']db=o['DB']+"."for k in o['attrs'].keys():tp=o['attrs'][k]['type']if tp=='real' :name=o['attrs'][k]['name']id=o['attrs'][k]['varid']add=o['attrs'][k]['add'].split('.')[0]add=db+addst2.append([id,sname+"."+name,-2,0,0,-10000,999999999,-1000,999999999,'否','否',o['plc'],add,'FLOAT',o['mode'],1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无','','',144])#st2.append([id,	sname+"."+name,0,0,0,-10000,999999999,-10000,999999999,'否','否',o['plc'],add,'FLOAT',o['mode'],1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无','',144,''])st2.append([])st2.append(['[IO离散]'])st2.append(['变量ID','变量名','变量使用记数','初始值','是否保存值','是否保存参数','设备名','寄存器名称','数据类型','读写属性','采集频率(毫秒)','是否允许DDE访问','报警组','优先级','是否产生报警','报警类型(开/关/变位)','关报警文本','开报警文本','开到关报警文本','关到开报警文本','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录/每次采集记录)','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])#st2.append(['变量ID','变量名','变量使用记数','初始值','是否保存值','是否保存参数','报警组','优先级','是否产生报警','报警类型(开/关/变位)','关报警文本','开报警文本','开到关报警文本','关到开报警文本','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])for o in dat:sname=o['name']db=o['DB']+"."for k in o['attrs'].keys():tp=o['attrs'][k]['type']if tp=='bool' :name=o['attrs'][k]['name']id=o['attrs'][k]['varid']add=db+o['attrs'][k]['add']#st2.append([id,sname+"."+name,0,'关','否','否',o['plc'],add,'Bit',o['mode'],1000,'否','',1,'否','','','','','','','','不记录','','否','无','',144,''])st2.append([id,sname+"."+name,-2,'关','否','否',o['plc'],add,'Bit',o['mode'],1000,'否','',1,'否','','','','','','','','不记录','','否','无','',144])st2.append([])st2.append(['[IO字符串]'])st2.append(['变量ID','变量名','变量使用记数','初始字符串(<127字节)','是否保存值','是否保存参数','设备名','寄存器名称','数据类型','读写属性','采集频率(毫秒)','是否允许DDE访问','安全区','注释','变量签名属性'])st2.append([])return varId
#------------------------------------------------------------------------------------------------------#比较两个结构体是否一样
def compStruct(a1,a2) :for nm in a1['attrs']:if nm['name'] not in a2['attrs'].keys(): return Falsereturn True#匹配结构体定义
def getStruct(obj):#print('get struct',obj)if 'attrs' not in obj.keys(): return Nonel1 = len(obj['attrs'])                                      #当前结构体属性数量for o in arr:l2=len(o['attrs'].keys())                              #目标结构体属性数量#print("@@",obj['name'],o['name'],l1,l2)if l1!=l2 : continue                                    #数量不匹配直接跳过if compStruct(obj,o) :                                 #如果比较成功了return oreturn None
#--------------------------------------------------------------------
# 解析对象的属性到已经定义的结构名称
# obj 是要转换的对象
# s 是已经定义的结构体
def transStruct(obj,s):for o in obj['attrs']:o['var']=s['attrs'][o['name']]['name']    #结构体变量名称return
#------------------------------------------------------------
#转换特定的名称,防止DB块里面拼写错误
def transName(nm):if nm in wordTrans.keys():return wordTrans[nm]return nm.replace('-','_').replace('#','_')
#----------------------------------------------------------
def formatStr(s):s1=s.replace(' ','').replace('\r','').replace('\n','').lower()#print(s,s1)return s1
#解析PDF
def readPDF(fname):if fname.find('.pdf')==-1 :returnplc=fname.split("_")[0]pdf=pdfplumber.open(fname)DB=getDBNum(pdf)print("dbname",DB)                              #结构体名称ss={}                                           #临时结构体for pg in pdf.pages:                            #循环所有页data =pg.extract_table()                    #获取表格for r in data :                             #循环所有行#print(r)name=transName(formatStr(r[0]))                    #名称,转换后的type=formatStr(r[1])                               #类型add=formatStr(r[2])                               #地址remark=r[13][0:35]                            #备注信息# print(name,type,remark)if name=='名称' or name=='w' or name.find('备用')!=-1:            #跳过无用的行#print('skip  '+name)continue#print(name,type)if type == 'struct':                    #如果是Struct ,可能是结构体开头structDef=getStruct(ss)             #寻找匹配的结构体#print("structDef",structDef)if  structDef != None :#print(" found struct",ss)transStruct(ss,structDef)       #转换到定义的名称ss['struct']=structDef['name']  #结构体变量名称ss['mode']=structDef['mode']    #读写属性objects.append(ss)              #添加到对象里面else :others.append(ss)               #添加到另外一个列表if name.find('static')!=-1:         #没有名字的结构体,跳过ss={}else :ss={'name':name,'remark':remark,'DB':DB,'plc':plc,'attrs':[]} #重置当前结构体continue                            #结构体开头行if name.find('static')==-1 and  'attrs' in ss.keys():                #如果存在这个属性,认为是一个合理的结构体ss['attrs'].append({'name':name,'type':type,'add':add,'remark':remark}) #增加一个属性return                                          #解析PDF结束
#-----------------------------------------------------------------------------------------------------------
#创建结构体变量
def createVar(objs,varId):print("struct len ",len(objs))startId=1   st1=wb.create_sheet("结构变量页")st2=wb.create_sheet("基本变量页")st1.append(['说明:本页为数据词典中所有结构变量  请不要编辑此行'])st2.append(['说明:本页为数据词典中所有基本变量  请不要编辑此行'])st2.append(['[内存整型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','是否保存值','是否保存参数','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])st2.append([''])st2.append(['[内存实型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','是否保存值','是否保存参数','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])st2.append([''])st2.append(['[内存离散]'])st2.append(['变量ID','变量名','变量使用记数','初始值','是否保存值','是否保存参数','报警组','优先级','是否产生报警','报警类型(开/关/变位)','关报警文本','开报警文本','开到关报警文本','关到开报警文本','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])st2.append([''])st2.append(['[内存字符串]'])st2.append(['变量ID','变量名','变量使用记数','初始字符串(<127字节)','是否保存值','是否保存参数','安全区','注释','变量签名属性'])st2.append([''])for o in objs:                                                                  #循环输出结构体变量页m='R'if o['mode']=='只写':m="W"sname=m+o['name'].upper()st1.append(['[结构变量]','变量ID','变量名','变量类型','变量使用记数','注释'])   #列st1.append(['',startId,sname,o['struct'],0,o['remark']])                #结构体st1.append(['','[成员]','成员名称','成员基本变量ID'])		              #成员变量列startId=startId+1sname=sname+"."for a in o['attrs']:a['varid']=varIdst1.append(['','',sname+a['var'].upper(),varId])		              #成员变量列varId=varId+1                                                     #变量id增加1个#################################################################st2.append(['[IO整型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','是否保存值','是否保存参数','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])for o in objs:                                                            #循环输出整数plc=o['plc']DB=o['DB']+"."struct=o['struct']mode=o['mode']m='R'if mode=='只写':m="W"sname=m+o['name'].upper()+"."for  a in o['attrs']:if a['type'] == 'int' or a['type']=='dint' :add=DB+a['add'].split(".")[0]tp='SHORT'if a['type']=='dint' : tp='LONG'st2.append([a['varid'],sname+a['var'].upper(),0,0,0,-10000,999999999,-10000,999999999,'否','否',plc,add,tp,mode,1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无',a['remark'],144,''])st2.append([''])#################################################################st2.append(['[IO实型]'])st2.append(['变量ID','变量名','变量使用记数','变化灵敏度','初始值','最小值','最大值','是否保存值','是否保存参数','报警组','优先级','低低限值','低低报警文本','低限值','低报警文本','高限值','高报警文本','高高限值','高高报警文本','越限死区','报警延时','变化率%','变化率单位','目标值','小偏差','大偏差','偏差死区','扩展域1','扩展域2','历史记录方式(不记录/变化记录/定时记录)','历史记录变化灵敏度','记录间隔(分)','是否生成操作事件','安全区','注释','变量签名属性'])for o in objs:                                                            #循环输出整数plc=o['plc']DB=o['DB']+"."struct=o['struct']mode=o['mode']m='R'if mode=='只写':m="W"sname=m+o['name'].upper()+"."for  a in o['attrs']:if a['type'] == 'real':add=DB+a['add'].split(".")[0]tp='FLOAT'st2.append([a['varid'],sname+a['var'].upper(),0,0,0,-10000,999999999,-10000,999999999,'否','否',plc,add,tp,mode,1000,'线性','无','','','','否','',1,'','','','','','','','','','','','','','','','','','','不记录','','','否','无',a['remark'],144,''])st2.append([''])#################################################################st2.append(['[IO离散]'])st2.append(['变量ID','变量名','变量使用记数','初始字符串(<127字节)','是否保存值','是否保存参数','安全区','注释','变量签名属性'])for o in objs:                                                            #循环输出整数plc=o['plc']DB=o['DB']+"."struct=o['struct']mode=o['mode']m='R'if mode=='只写':m="W"sname=m+o['name'].upper()+"."for  a in o['attrs']:if a['type'] == 'bool' :add=DB+a['add']     st2.append([a['varid'],sname+a['var'].upper(),0,'关','否','否',plc,add,'Bit',mode,1000,'否','',1,'否','','','','','','','','不记录','','否','无',a['remark'],144,''])st2.append([''])return#---------------------------------------------------------------path='./'arr=[]      #存储定义好的结构体
objects=[]  #所有数据
others=[]   #没有写进去的
wb =Workbook()                              #用于导出excel文件
types={'bool':'离散型','int':'整型','dint':'整型','real':'实型'}wordTrans={'chuchanqirukouyali':'chuchenqirukouyali','zhaunsufankui':'fankuizhuansu','zhuansufankui':'fankuizhuansu','bstate_ready_1':'bstate_ready','bstate_fault_1':'bstate_fault'} #有些拼错的,使用这个转换一下def getDBNum(pdf):                                  #解析DB块号tb=pdf.pages[0].extract_tables()[1]             #获取第一页name=tb[2][1]                                   #DB块注释dbNum=tb[2][3]                                  #DB块号print(name,dbNum)return 'DB' +dbNum# 打开JSON文件
with open('data.json', 'r',encoding='utf-8') as f:# 读取文件内容arr = json.load(f)# 创建结构体定义
varId=createStruct(arr)# 遍历当前目录
for file_name in os.listdir(path):# 处理目录中的文件或子目录full_path = os.path.join(path, file_name)  # 拼接文件或子目录的完整路径if os.path.isfile(full_path):  # 判断是否为文件print("文件:", file_name)readPDF(file_name)#print(objects)elif os.path.isdir(full_path):  # 判断是否为子目录print("子目录:", file_name)
#创建变量定义
createVar(objects,varId)
wb.save('test.xls')  print(others)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/58530.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka相关API开发

(一)引入依赖 用API直接去操作kafka(读写数据)在实际开发中用的并不多&#xff0c;学习它主要还是为了加深对Kafka功能的理解。kafka的读写操作&#xff0c;实际开发中&#xff0c;是通过各类更上层的组件去实现。而这些组件在读写kafka数据时&#xff0c;用的当然是kafka的jav…

linux离线安装Ollama并完成大模型配置(无网络)

这篇文章主要分享两方面内容&#xff1a; 1&#xff09;在纯内网环境下如何部署ollama 2&#xff09;在纯内网环境下如何配置大模型 话不多说直接开始。 ①离线部署ollama 一、通过浏览器访问ollama官方安装脚本&#xff0c;获取脚本内容。复制里面的内容。 在Linux中执行…

Centos安装配置Jenkins

下载安装 注意&#xff1a;推荐的LTS版本对部分插件不适配&#xff0c;直接用最新的版本&#xff0c;jenkins还需要用到git和maven&#xff0c;服务器上已经安装&#xff0c;可查看参考文档[1]、[2]&#xff0c;本次不再演示 访问开始使用 Jenkins 下载jenkins 上传至服务器…

【java数据结构】二叉树

【java数据结构】二叉树 一、 认识二叉树1.1 二叉树的概念1.2 二叉树的特性&#xff1a;1.3 两种特殊的二叉树&#xff1a;1.4 二叉树的性质&#xff1a;1.5 二叉树的存储&#xff1a; 二、 实现二叉树2.1 二叉树节点的定义&#xff1a;2.2 二叉树的基本操作&#xff1a;获取树…

智源推出小时级超长视频理解大模型Video-XL

北京智源人工智能研究院联合上海交通大学、中国人民大学、北京大学和北京邮电大学等高校推出了一款名为Video-XL的超长视频理解大模型。这款模型是多模态大模型核心能力的重要展示&#xff0c;也是向通用人工智能&#xff08;AGI&#xff09;迈进的关键步骤。与现有多模态大模型…

《链表篇》---两两交换链表中的节点(中等)

题目传送门 1.定义一个虚拟节点链接链表 2.定义一个当前节点指向虚拟节点 3.在当前节点的下一个节点和下下一个节点都不为null的情况下。 定义 node1和node2。保存当前节点后面两个节点的地址。cur.next node2;node1.next node2.next;node2.next node1;cur node1; 4.返回re…

Oracle视频基础1.3.4练习

1.3.4 检查数据库实例启动情况&#xff0c;进程以及进程间通信 ps -ef | grep oracle ipcs启动数据库实例&#xff0c; 用缺省spfilewilson ls -l env | grep ORACLE sqlplus /nolog conn / as sysdba startup shutdown immediate exit clear新创建pfile和spfile指定pfile数…

图书管理系统汇报

【1A536】图书管理系统汇报 项目介绍1.用户登录注册功能1. 1用户角色管理2.图书管理功能2.1 添加图书2.2 编辑图书2.3 删除图书 3.图书搜索和筛选3.1 图书搜索3.2 图书筛选 4.图书借阅、图书归还4.1 图书借阅4.2 图书归还 5.用户信息管理5.1上传头像5.2修改头像5.3 修改密码 项…

JetCache启动循环依赖分析

问题呈现 项目性能优化&#xff0c;需要将本地内存&#xff08;JVM内存&#xff09;替换为本地Redis&#xff08;同一个Pod中的Container&#xff09;&#xff0c;降低JVM内存和GC的压力&#xff0c;同时引入了JetCache简化和统一使用&#xff08;对JetCache也做了扩展&#x…

使用二进制安装K8S 多master节点 高可用集群

目录 1.初始化 1.1 配置静态IP 1.2 配置主机名 1.3 配置hosts文件 1.4 配置主机之间无密码登录&#xff0c;每台机器都按照如下操作 1.5 关闭firewalld防火墙&#xff0c;在xianchaomaster1、xianchaomaster2、xianchaomaster3、xianchaonode1上操作&#xff1a; 1.…

vue的基本使用

简介 vue组件 三个部分组成&#xff1a;结构、样式、逻辑 文本插值 类似于java的spel表达式 属性绑定 綁定是单向绑定的&#xff0c;修改输入框无法改变原本的&#xff0c;只能读&#xff0c;不能写 <input :value"name" placeholder"Type your name"&g…

从APP小游戏到Web漏洞的发现

一、前因&#xff1a; 在对一次公司的一个麻将游戏APP进行渗透测试的时候发现&#xff0c;抓到HTTP请求的接口&#xff0c;但是反编译APK后发现没有在本身发现任何一个关于接口或者域名相关的关键字&#xff0c;对此感到了好奇。 于是直接解压后everything搜索了一下&#xff…

【有啥问啥】视频插帧算法技术原理详解

视频插帧算法技术原理详解 引言 视频插帧&#xff08;Video Interpolation&#xff09;技术&#xff0c;作为计算机视觉领域的一项重要应用&#xff0c;旨在通过算法手段在已有的视频帧之间插入额外的帧&#xff0c;从而提升视频的帧率&#xff0c;使其看起来更加流畅。这一技…

【温酒笔记】DMA

参考文档&#xff1a;野火STM32F103 网友资料整理 1. Direct Memory Access-直接内存访问 DMA控制器独立于内核 是一个单独的外设 DMA1有7个通道DMA2有5个通道DMA有四个等级&#xff0c;非常高&#xff0c;高&#xff0c;中&#xff0c;低四个优先级如果优先等级相同&#xf…

精选云手机平台推荐:五大知名云手机品牌汇总

云手机目前已经在很多行业开始应用&#xff0c;特别是对于需要多设备操作、稳定性能和账号安全保障的用户。下面就为大家推荐几款优质云手机平台&#xff0c;一起来看看各大品牌有什么优势。 1. Ogphone云手机 Ogphone云手机凭借强大的海外网络连接和群控性能受到各行业用户的欢…

C++设计模式结构型模式———适配器模式

文章目录 一、引言二、适配器模式三、类适配器四、总结 一、引言 适配器模式是一种结构型设计模式&#xff0c;它在日常生活中有着广泛的应用&#xff0c;比如各种转换接头和电源适配器&#xff0c;它们的主要作用是解决接口不兼容的问题。就像使用电源适配器将220V的市电转换…

生产车间怎么管?设备、生产、物料管理方法更好

我们都知道&#xff0c;面对竞争激烈的大环境&#xff0c;生产车间对于企业的重要性不言而喻&#xff0c;它是企业发展的关键所在。 生产车间管理是一项复杂且系统性很强的工作&#xff0c;涉及多个重要方面。其中&#xff0c;人员管理是核心之一&#xff0c;员工作为生产活动…

Prometheus套装部署到K8S+Dashboard部署详解

1、添加helm源并更新 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update2、创建namespace kubectl create namespace monitoring 3、安装Prometheus监控套装 helm install prometheus prometheus-community/prome…

Redis 主从同步 总结

前言 相关系列 《Redis & 目录》《Redis & 主从同步 & 源码》《Redis & 主从同步 & 总结》《Redis & 主从同步 & 问题》 参考文献 《Redis的主从复制和哨兵机制详解》 概述 简介 主从同步的本质是数据复制机制。主从同步机制用于将master…

认证鉴权框架之—sa-token

一、概述 Satoken 是一个 Java 实现的权限认证框架&#xff0c;它主要用于 Web 应用程序的权限控制。Satoken 提供了丰富的功能来简化权限管理的过程&#xff0c;使得开发者可以更加专注于业务逻辑的开发。 二、逻辑流程 1、登录认证 &#xff08;1&#xff09;、创建token …