import os import shutil import subprocess import time from PyQt5.QtCore import QTimer import sys import zipfile sys.path.append('../../') import json from model.ClientModel.Client import Client from model.HistoryDBModel.HistoryDBManage import HistoryDBManage from model.ProjectModel.VarManage import TcRtdManage, AnalogManage, HartVarManage, \ HartSimulateVarManage from model.UserModel.UserManage import UserManage from utils import Globals from utils.DBModels.ClientModels import Project, ClientDB from utils.DBModels.ProjectBaseModel import * from utils.DBModels.ProtocolModel import ModbusTcpMasterVar, ModbusRtuMasterVar, ModbusRtuSlaveVar,\ ModbusTcpSlaveVar, TCPSetting, RTUSetting, InfluxMem, HartVar, TcRtdVar, AnalogVar, HartSimulateVar from utils.DBModels.UserModels import User from utils.DBModels.DeviceModels import DeviceDB from protocol.ProtocolManage import ProtocolManage class ProjectManage(object): """工程管理类""" def __init__(self): super(ProjectManage, self).__init__() @classmethod def createProject(self, name, des): # 创建工程 name = str(name) des = str(des) Client.initDB() if Project.getByName(name): return '已有同名工程' else: os.mkdir(os.path.join('project', name)) os.mkdir(os.path.join('project', name, 'db')) os.mkdir(os.path.join('project', name, 'config')) os.mkdir(os.path.join('project', name, 'log')) with open(os.path.join('project', name, 'config', 'config.json'), 'w') as f: json.dump({'description' : des}, f) project = Project() project.createProject(name, des) dbPath = os.path.join('project', name, 'db', 'project.db') projectDB = SqliteDatabase(dbPath) project_proxy.initialize(projectDB) projectDB.connect() projectDB.create_tables([ModbusTcpMasterVar, ModbusRtuMasterVar, ModbusRtuSlaveVar, ModbusTcpSlaveVar, User, TCPSetting, RTUSetting, HartVar, TcRtdVar, HartSimulateVar, AnalogVar, InfluxMem, DeviceDB],safe=True) manageList = [HartVarManage(), AnalogManage(), TcRtdManage(), HartSimulateVarManage()] for l in manageList: l.initVar() UserManage.initUser() modbusMasterTcpSetting = TCPSetting() modbusMasterTcpSetting.initSetting('master') modbusSlaveTcpSetting = TCPSetting() modbusSlaveTcpSetting.initSetting('slave') modbusMasterRtuSetting = RTUSetting() modbusMasterRtuSetting.initSetting('master') modbusMasterRtuSetting = RTUSetting() modbusMasterRtuSetting.initSetting('slave') projectDB.close() @classmethod def deleteProject(self, name): # 删除工程 name = str(name) # print(name) # print(Globals.getValue('currentPro')) Client.initDB() if not Project.getByName(name): print('不存在的工程', Project.getByName(name)) return try: if name == Globals.getValue('currentPro'): self.closePopen() Globals.getValue('protocolManage').shutdown() Globals.getValue('currentProDB').close() Globals.setValue('currentPro', None) QTimer.singleShot(1000, lambda:shutil.rmtree(os.path.join('project', name))) except OSError as e: print(e) Project.deleteProject(name = name) histroyTableName = 'p' + name HistoryDBManage.deleteTable(table=histroyTableName) @classmethod def switchProject(self, name): # 切换工程 currentDB = Globals.getValue('currentProDB') currentProtocolManage = Globals.getValue('protocolManage') if currentDB: currentDB.close() if Globals.getValue('protocolManage'): currentProtocolManage.shutdown() Client.initDB() dbPath = os.path.join('project', name, 'db', 'project.db') if ClientDB.getByName(): ClientDB.update(value = name).where(ClientDB.currentProject == '0').execute() else: clientDB = ClientDB() clientDB.createMes(name) projectDB = SqliteDatabase(dbPath) project_proxy.initialize(projectDB) projectDB.connect() self.closePopen() Globals.setValue('currentPro', name) Globals.setValue('currentProDB', projectDB) Globals.setValue('currentProType', 1)#切换工程 histroyTableName = 'p' + name historyDBManage = HistoryDBManage(table=histroyTableName) Globals.setValue('historyDBManage', historyDBManage) # protocolManage.writeVariableValue('无源4-20mA输出通道1', 150) # protocolManage.writeVariableValue('有源24V数字输出通道12', 1) # protocolManage.writeVariableValue('热偶输出2', 40) # protocolManage.writeVariableValue('热阻输出3', 50) # print(protocolManage.readVariableValue('有源/无源4-20mA输入通道2')) # print(protocolManage.readVariableValue('无源24V数字输入通道2')) # print(a) # print(Globals.getValue('historyDBManage')) protocolManage = ProtocolManage() Globals.setValue('protocolManage', protocolManage) Globals.getValue('HistoryWidget').exchangeProject() # if Globals.getValue('FFThread').isRunning(): # Globals.getValue('FFThread').reStart() # return # initDB @classmethod def closePopen(self): if Globals.getValue('currentProType') == '5': RTDTCThread = Globals.getValue('RTDTCThread') RTDTCThread.pause() RTDTCThread.RTDTCCom.quit() elif Globals.getValue('currentProType') == '6': AnalogThread = Globals.getValue('AnalogThread') AnalogThread.pause() AnalogThread.AnalogCom.close() elif Globals.getValue('currentProType') == '7': Globals.getValue('FFThread').pause() elif Globals.getValue('currentProType') == '8': FFSimulateThread = Globals.getValue('FFSimulateThread') FFSimulateThread.pause() FFSimulateThread.FFSimulate.stop() elif Globals.getValue('currentProType') == '9': HartSimulateThread = Globals.getValue('HartSimulateThread') HartSimulateThread.pause() HartSimulateThread.HartSimulate.stop() popen = Globals.getValue('popen') popenBeat = Globals.getValue('beatPopen') if popen: popen.kill() Globals.setValue('popen', None) if popenBeat: popenBeat.kill() Globals.setValue('beatPopen', None) @classmethod def startProtocol(self): # 0 : MODBUSTCP 主站模式 # 1 : MODBUSTCP 从站模式 # 2 : MODBUSRTU 主站模式 # 3 : MODBUSRTU 从站模式 # 5 : RTD/TC proType = Globals.getValue('currentProType') if proType == '0': popen = subprocess.Popen("celery -A MBTCPMTask worker -l error -P eventlet --purge", stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBTCPMaster') QTimer.singleShot(5000, lambda:self.startBeat(proType)) elif proType == '1': popen = subprocess.Popen("celery -A MBTCPSTask worker -l error -P solo -c 2 --purge", stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBTCPSlave') QTimer.singleShot(5000, lambda:self.startBeat(proType)) elif proType == '2': popen = subprocess.Popen("celery -A MBRTUMTask worker -l error -P solo -c 2 --purge", stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBRTUMaster') QTimer.singleShot(5000, lambda:self.startBeat(proType)) elif proType == '3': popen = subprocess.Popen("celery -A MBRTUSTask worker -l error -P solo -c 2 --purge", stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBRTUSlave') QTimer.singleShot(5000, lambda:self.startBeat(proType)) elif proType == '4': popen = subprocess.Popen("celery -A HARTTask worker -l error -P solo -c 2 --purge", stdout=subprocess.PIPE, cwd = 'protocol/Celery/HARTCelery') QTimer.singleShot(5000, lambda:self.startBeat(proType)) # popenBeat = subprocess.Popen('celery -A HARTTask beat', stdout=subprocess.PIPE, cwd = 'protocol/Celery/HARTCelery') elif proType == '5': RTDTCThread = Globals.getValue('RTDTCThread') RTDTCThread.RTDTCCom.start() if RTDTCThread.isRunning(): RTDTCThread.reStart() else: RTDTCThread.start() return elif proType in ['6']: AnalogThread = Globals.getValue('AnalogThread') AnalogThread.AnalogCom.connect() AnalogThread.start() return elif proType in ['8']: FFSimulateThread = Globals.getValue('FFSimulateThread') FFSimulateThread.FFSimulate.start() FFSimulateThread.start() return elif proType in ['9']: HartSimulateThread = Globals.getValue('HartSimulateThread') HartSimulateThread.HartSimulate.start() HartSimulateThread.start() return else: return Globals.setValue('popen', popen) # popen.kill() @classmethod def startBeat(self, proType): if proType == '0': popenBeat = subprocess.Popen('celery -A MBTCPMTask beat', stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBTCPMaster') elif proType == '1': popenBeat = subprocess.Popen('celery -A MBTCPSTask beat', stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBTCPSlave') elif proType == '2': popenBeat = subprocess.Popen('celery -A MBRTUMTask beat', stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBRTUMaster') elif proType == '3': popenBeat = subprocess.Popen('celery -A MBRTUSTask beat', stdout=subprocess.PIPE, cwd = 'protocol/Celery/MBRTUSlave') elif proType == '4': popenBeat = subprocess.Popen('celery -A HARTTask beat', stdout=subprocess.PIPE, cwd = 'protocol/Celery/HARTCelery') Globals.setValue('beatPopen', popenBeat) @classmethod def recordingHistory(self, projectName, cursor): # 记录打开通讯的时间 并创建INFLUXDB表 curTime = time.time() # influxMem = InfluxMem() # influxMem.createMem(time) curTime = float("{:.5f}".format(curTime)) cursor.execute('insert into InfluxMem (mem) values ({})'.format(str(curTime))) historyDB = HistoryDBManage(mem = curTime, bucket = projectName, isCelery = True) return historyDB @classmethod def editProject(self, name, Nname, des): # 修改工程信息 name = str(name) Nname = str(Nname) des = str(des) Client.initDB() if name == Nname: if name == Globals.getValue('currentPro'): self.editCurProject(name, Nname, des) return Project.update(projectName = Nname, description = des).where(Project.projectName == name).execute() QTimer.singleShot(1000, lambda:os.rename(os.path.join('project', name), os.path.join('project', Nname))) elif Project.getByName(Nname): return '已有同名工程' elif not Project.getByName(name): print('不存在的工程') return else: if name == Globals.getValue('currentPro'): self.editCurProject(name, Nname, des) return Project.update(projectName = Nname, description = des).where(Project.projectName == name).execute() QTimer.singleShot(1000, lambda:os.rename(os.path.join('project', name), os.path.join('project', Nname))) @classmethod def editCurProject(self, name, Nname, des): self.closePopen() Globals.getValue('currentProDB').close() Project.update(projectName = Nname, description = des).where(Project.projectName == name).execute() QTimer.singleShot(1000, lambda:self.reNameCurProDir(name, Nname)) Globals.getValue('MainWindow').varWidget.initIcon() Globals.setValue('currentPro', Nname) @classmethod def reNameCurProDir(self, name, Nname): os.rename(os.path.join('project', name), os.path.join('project', Nname)) self.switchProject(Nname) @classmethod def getAllProject(self): # 查询所有工程 projects = Project.get_all() if projects is 'error': return l = [] for x in projects: l.append([x.id, x.projectName, x.description, x.createTime]) return l @classmethod def getByName(self, name): # 查询指定工程信息 project = Project.getByName(name) if project: return [project.id, project.projectName, project.description, project.createTime] else: return False @classmethod def exportProject(self, zipName, projects): """ 将多个文件夹打包成一个zip文件。 :param projects: 要打包的工程列表 :param zipName: 结果zip文件的名称 """ folders = [os.path.join('project', project) for project in projects] with zipfile.ZipFile(zipName, 'w', zipfile.ZIP_DEFLATED) as zipf: for folder in folders: for root, dirs, files in os.walk(folder): for file in files: # 获取文件路径 filePath = os.path.join(root, file) # 获取文件相对于根目录的相对路径 relPath = os.path.join(*filePath.split(os.sep)[-3:]) # 使用修改后的路径将文件写入归档文件 zipf.write(filePath, arcname=relPath) if not dirs and not files: # 获取文件夹路径 folderPath = os.path.join(root) # 获取文件夹相对于根目录的相对路径 relPath = os.path.join(*folderPath.split(os.sep)[-2:]) # 使用修改后的路径将文件夹写入归档文件 zipInfo = zipfile.ZipInfo(relPath + '/') zipf.writestr(zipInfo, '') # To parse a zip file and get the list of folders inside it, use the following code: @classmethod def importProject(self, zipName): l = self.getAllProject() allName = [x[1] for x in l] with zipfile.ZipFile(zipName, 'r') as zipf: zipProjects = set() repeatProject = set() [zipProjects.add(x.split('/')[0]) for x in zipf.namelist()] for projectName in allName: if projectName in zipProjects: repeatProject.add(projectName) if repeatProject: return repeatProject zipf.extractall('project') projectList = [] for n in zipProjects: jsonPath = os.path.join('project', n, 'config', 'config.json') with open(jsonPath, 'r') as f: data = json.load(f) # proType = data['ProjectType'] des = data['description'] project = Project() project.createProject(n, des) projectList.append(n) return projectList # ProjectManage.importProject('1.project')