You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			465 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			465 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Python
		
	
| import collections
 | |
| import json
 | |
| from utils.DBModels.DeviceModels import DeviceDB
 | |
| import numpy as np
 | |
| from protocol.ModBus.ByteOrder import *
 | |
| from protocol.ModBus.TCPMaster import *
 | |
| import struct
 | |
| import time
 | |
| #从站 "AI" "DI"可强制
 | |
| #主站 "AO" "DO"可强制
 | |
| 
 | |
| class Area():
 | |
|     startAddress = None
 | |
|     endAddress = None
 | |
|     bytes = None
 | |
|     type = None
 | |
|     addressList = []
 | |
|     order = 'ABCD'
 | |
|     nums = 0
 | |
|     forceValue = [0]
 | |
|     currentValue = [0] * nums
 | |
|     qualityValueList = []
 | |
|     def __init__(self):
 | |
|         pass
 | |
| 
 | |
| class Device():
 | |
|     inputStartAddress = 0
 | |
|     inputEndAddress = 0
 | |
|     outputStartAddress = 0
 | |
|     outputEndAddress = 0
 | |
|     protocolType = None
 | |
|     masterOrSlave = None
 | |
|     deviceName = None
 | |
|     def __init__(self):
 | |
|         self.inputAreas = []
 | |
|         self.outputAreas = []
 | |
|         self.areas = []
 | |
|         self.indexDict = collections.OrderedDict()
 | |
|         # 有序字典 键:总区域索引 值: [类型(输入 : 0, 或输出 : 1), 该类型的第几个区域索引]
 | |
| 
 | |
|     def addArea(self, type, nums, bytes, order = 'ABCD', valueName = None):
 | |
|         area = Area()
 | |
|         bytes = int(bytes)
 | |
|         area.type = type
 | |
|         area.order = order
 | |
|         area.bytes = bytes
 | |
|         area.valueName = valueName
 | |
|         area.length = self.getLength(nums, bytes)
 | |
|         area.nums = nums
 | |
|         area.currentValue = [0] * nums
 | |
|         if type in ["AI", "DI"]:
 | |
|             area.startAddress = 0 if not self.inputEndAddress else self.inputEndAddress
 | |
|             area.endAddress = area.startAddress + area.length
 | |
|             # print(area.startAddress, area.endAddress)
 | |
|             self.inputEndAddress = area.endAddress
 | |
|             area.addressList = np.arange(area.startAddress, area.endAddress + 1, area.bytes).tolist()
 | |
|             self.indexDict[len(self.indexDict.values())] = [0, len(self.inputAreas)]
 | |
|             self.inputAreas.append(area)
 | |
|             self.areas.append(area)
 | |
|         elif type in ["DO" , "AO"]:
 | |
|             area.startAddress = 0 if not self.outputEndAddress else self.outputEndAddress
 | |
|             area.endAddress = area.startAddress + area.length
 | |
|             self.outputEndAddress = area.endAddress
 | |
|             area.addressList = np.arange(area.startAddress, area.endAddress + 1, area.bytes).tolist()
 | |
|             self.indexDict[len(self.indexDict.values())] = [1, len(self.outputAreas)]
 | |
|             self.outputAreas.append(area)
 | |
|             self.areas.append(area)
 | |
|         if (self.masterOrSlave == '主站' and type in ['AI', 'DI']) or (self.masterOrSlave == '从站' and type in ['AO', 'DO']):
 | |
|             return True
 | |
|         # print(id(self), self.inputAreas)
 | |
|         # print(self.deviceName, area.addressList, area.startAddress, area.endAddress, self.inputAreas)
 | |
| 
 | |
|     def delArea(self, index, type):
 | |
|         if type in ["DI", "AI"]:
 | |
|             self.inputAreas.pop(self.indexDict[index][1])
 | |
|         elif type in ["AO", "DO"]:
 | |
|             self.outputAreas.pop(self.indexDict[index][1])
 | |
|         # self.indexDict.pop(index)
 | |
|         newDict = collections.OrderedDict()
 | |
|         rmValue = self.indexDict[index]
 | |
|         for key, value in self.indexDict.items():
 | |
|             # print(value)
 | |
|             if key < index:
 | |
|                 newDict[key] = value
 | |
|             elif key > index:
 | |
|                 if value[0] == rmValue[0]:
 | |
|                     newDict[key - 1] = [value[0], value[1] - 1]  # 更新类型索引和区域索引
 | |
|                 else:
 | |
|                     newDict[key - 1] = [value[0], value[1]]
 | |
| 
 | |
|         self.indexDict = newDict
 | |
|         self.areas.pop(index)
 | |
|         self.recalculateAddress()
 | |
| 
 | |
|     def recalculateAddress(self):
 | |
|         # print(self.inputStartAddress)
 | |
|         for inputOrOutput, areas in enumerate([self.inputAreas, self.outputAreas]):
 | |
|             endAddress = 0
 | |
|             for index, area in enumerate(areas):
 | |
|                 if index == 0 and inputOrOutput == 0:
 | |
|                     area.startAddress = self.inputStartAddress
 | |
|                 elif index == 0 and inputOrOutput == 1:
 | |
|                     area.startAddress = self.outputStartAddress
 | |
|                 else:
 | |
|                     area.startAddress = areas[index - 1].endAddress
 | |
|                 area.endAddress = area.startAddress + area.length
 | |
|                 area.addressList = np.arange(area.startAddress, area.endAddress + 1, area.bytes).tolist()
 | |
|                 # print(area.addressList, area.startAddress, area.endAddress, self.deviceName)
 | |
|                 endAddress = area.endAddress
 | |
|                 # print(self.deviceName, area.startAddress, area.endAddress, area.bytes, time.time())
 | |
|                 # print(endAddress)
 | |
|             # else:
 | |
|             #     print(endAddress)
 | |
|             if endAddress == 0 and inputOrOutput == 0:
 | |
|                 endAddress = self.inputStartAddress
 | |
|             if endAddress == 0 and inputOrOutput == 1:
 | |
|                 endAddress = self.outputStartAddress
 | |
|             if inputOrOutput == 0:
 | |
|                 self.inputEndAddress = endAddress
 | |
|             elif inputOrOutput == 1:
 | |
|                 self.outputEndAddress = endAddress
 | |
|                 # endAddress = 0
 | |
| 
 | |
|     def editArea(self, index, type, order, bytes):
 | |
|         # if type in ["DI", "AI"]:
 | |
|         #     self.inputAreas[self.indexDict[index]].order = order
 | |
|         #     self.inputAreas[self.indexDict[index]].bytes = bytes
 | |
|         # elif type in ["AO", "DO"]:
 | |
|         #     self.outputAreas[self.indexDict[index]].order = order
 | |
|         #     self.outputAreas[self.indexDict[index]].bytes = bytes
 | |
|         # print(bytes)
 | |
|         # print(self.areas[index])
 | |
|         self.areas[index].order = order
 | |
|         self.areas[index].bytes = bytes
 | |
|         self.areas[index].length = int(self.areas[index].nums) * int(bytes)
 | |
|         # self.recalculateAddress()
 | |
| 
 | |
| 
 | |
|     def getAreaValues(self, index):
 | |
|         # if self.masterOrSlave == "从站":
 | |
|         #     return self.outputAreas[index].currentValue
 | |
|         # else:
 | |
|         #     # print(self.inputAreas, index)
 | |
|         #     # print(id(self), self.inputAreas)
 | |
|         #     return self.inputAreas[index].currentValue
 | |
|         # print(self.areas[index].currentValue)
 | |
|         return self.areas[index].currentValue, self.areas[index].qualityValueList
 | |
| 
 | |
|     def getLength(self, nums, bytes):
 | |
|         length = int(nums) * int(bytes)
 | |
|         # length = length / 2
 | |
|         return length
 | |
| 
 | |
| 
 | |
| 
 | |
|     
 | |
|                 
 | |
| 
 | |
|     @classmethod
 | |
|     def delAreas(self, deviceName, id):
 | |
|         jsonCon = json.loads(DeviceDB.getByName(deviceName=deviceName).areaJson)
 | |
|         if len(jsonCon) > id:
 | |
|             jsonCon.pop(id)
 | |
|         else:
 | |
|             return
 | |
| 
 | |
|         if jsonCon == []:
 | |
|             areaJson = '[]'
 | |
|             DeviceDB.update(areaJson=areaJson).where(DeviceDB.deviceName == deviceName).execute()
 | |
|         else:
 | |
|             for index, areajsonId in enumerate(jsonCon):
 | |
|                 areajsonId["id"] = index
 | |
|             areaJson = json.dumps(jsonCon)
 | |
|          
 | |
|             DeviceDB.update(areaJson=areaJson).where(DeviceDB.deviceName == deviceName).execute()
 | |
| 
 | |
| 
 | |
|     @classmethod
 | |
|     def getAreaJson(self, deviceNames):
 | |
|         deviceName = deviceNames
 | |
|         jsonConsStr = json.loads(DeviceDB.getByName(deviceName=deviceName).areaJson)
 | |
|         if jsonConsStr == []:
 | |
|             return
 | |
|         else:
 | |
|             jsonCons = json.loads(jsonConsStr)
 | |
|             return jsonCons
 | |
| 
 | |
| 
 | |
| 
 | |
| class DevicesManange():
 | |
|     def __init__(self):
 | |
|         self.dpMasterDevices = collections.OrderedDict()
 | |
|         self.dpSlaveDevices = collections.OrderedDict() # 有序字典 (OrderedDict)
 | |
|         self.paMasterDevices = collections.OrderedDict()
 | |
|         self.paSlaveDevices = collections.OrderedDict()
 | |
|     def connect(self):
 | |
|         self.dpSlaveModbus = TcpMaster(host = '192.168.2.10', port = 502)
 | |
|         self.paSlaveModbus = TcpMaster(host = '192.168.4.10', port = 502)
 | |
|         self.dpMasterModbus = TcpMaster(host = '192.168.1.10', port = 502)
 | |
|         self.paMasterModbus = TcpMaster(host = '192.168.3.10', port = 502)
 | |
| 
 | |
| 
 | |
| 
 | |
|     def addDevice(self, proType, masterSlaveModel, deviceName):
 | |
|         device = Device()
 | |
|         device.type = proType
 | |
|         device.masterOrSlave = masterSlaveModel
 | |
|         device.deviceName = deviceName
 | |
| 
 | |
|         if proType == "DP" and masterSlaveModel == "主站":
 | |
|             curProDict = self.dpMasterDevices
 | |
|         elif proType == "DP" and masterSlaveModel == "从站":
 | |
|             curProDict = self.dpSlaveDevices
 | |
|         elif proType == "PA" and masterSlaveModel == "主站":
 | |
|             curProDict = self.paMasterDevices
 | |
|         elif proType == "PA" and masterSlaveModel == "从站":
 | |
|             curProDict = self.paSlaveDevices
 | |
| 
 | |
|         if len(curProDict) == 0:
 | |
|             device.inputStartAddress = 0
 | |
|             device.outputStartAddress = 0
 | |
|         else:
 | |
|             device.inputStartAddress = list(curProDict.values())[-1].inputEndAddress
 | |
|             device.outputStartAddress = list(curProDict.values())[-1].outputEndAddress
 | |
|         curProDict[deviceName] = device
 | |
| 
 | |
|     def initDevices(self):
 | |
|         pass
 | |
| 
 | |
|     def delDevice(self, deviceName):
 | |
|         for devicesDict in [self.paMasterDevices, self.paSlaveDevices, self.dpMasterDevices, self.dpSlaveDevices]:
 | |
|             if deviceName in devicesDict:
 | |
|                 del devicesDict[deviceName]
 | |
|                 self.recalculateAddress()
 | |
| 
 | |
|     def recalculateAddress(self):
 | |
|         for devicesDict in [self.paMasterDevices, self.paSlaveDevices, self.dpMasterDevices, self.dpSlaveDevices]:
 | |
|             # print(len(devicesDict))
 | |
|             # print(devicesDict)
 | |
|             # print(self.dpMasterDevices)
 | |
|             for index, (deviceName, device) in enumerate(devicesDict.items()):
 | |
|                 if index == 0:
 | |
|                     device.inputStartAddress = 0
 | |
|                     device.outputStartAddress = 0
 | |
|                 else:
 | |
|                     inputAddress = list(devicesDict.values())[index - 1].inputEndAddress
 | |
|                     outputAddress = list(devicesDict.values())[index - 1].outputEndAddress
 | |
|                     device.inputStartAddress = 0 if inputAddress == 0 else inputAddress
 | |
|                     device.outputStartAddress = 0 if outputAddress == 0 else outputAddress
 | |
|                 # print(device.inputStartAddress, device.inputEndAddress, deviceName, '输入')
 | |
|                 device.recalculateAddress()
 | |
|                 # print(device.outputStartAddress, device.outputEndAddress, deviceName)
 | |
|                 # print(device.outputStartAddress, device.outputEndAddress, deviceName, 'shuchu')
 | |
|                 # previousDevice = device
 | |
| 
 | |
| 
 | |
|     def getDevice(self, deviceName):
 | |
|         for devicesDict in [self.paMasterDevices, self.paSlaveDevices, self.dpMasterDevices, self.dpSlaveDevices]:
 | |
|             if deviceName in devicesDict:
 | |
|                 return devicesDict[deviceName]
 | |
| 
 | |
|     def writeAreas(self, deviceName, areaIndex, values, qualityValueList = None):
 | |
|         # print(values)
 | |
|         bytes = b""
 | |
|         device = self.getDevice(deviceName)
 | |
|         # print(device, deviceName)
 | |
|         if device.type == "DP" and device.masterOrSlave == "主站":
 | |
|             curProDict = self.dpMasterDevices
 | |
|             # areas = device.outputAreas
 | |
|             modbusM = self.dpMasterModbus
 | |
|         elif device.type == "DP" and device.masterOrSlave == "从站":
 | |
|             curProDict = self.dpSlaveDevices
 | |
|             # areas = device.inputAreas
 | |
|             modbusM = self.dpSlaveModbus
 | |
|         elif device.type == "PA" and device.masterOrSlave == "主站":
 | |
|             # areas = device.outputAreas
 | |
|             curProDict = self.paMasterDevices
 | |
|             modbusM = self.paMasterModbus
 | |
|         elif device.type == "PA" and device.masterOrSlave == "从站":
 | |
|             # areas = device.inputAreas
 | |
|             curProDict = self.paSlaveDevices
 | |
|             modbusM = self.paSlaveModbus
 | |
|         # print(values)
 | |
|         # for area, value in zip(areas, values):
 | |
|         area = device.areas[areaIndex]
 | |
|         area.forceValue = values
 | |
|         area.qualityValueList = qualityValueList
 | |
|         if area.type in ['DO', 'DI'] and device.type == 'PA':
 | |
|             area.forceValue = values[8:] + values[:8]
 | |
|         elif area.type in ['DO', 'DI'] and device.type == 'DP' and device.masterOrSlave == "主站":
 | |
|             area.forceValue = values[8:] + values[:8]
 | |
| 
 | |
|         for device in curProDict.values():
 | |
|             forceAreas = device.outputAreas if device.masterOrSlave == "主站" else device.inputAreas
 | |
|             for area in forceAreas:
 | |
|                 # print(area.forceValue)
 | |
|                 if area.type in ["AI", "AO"]:
 | |
|                     # print(area.forceValue)
 | |
|                     byte = floatToBytes(area.forceValue, area.bytes, order = area.order, qualityValueList = area.qualityValueList)
 | |
|                     # print(type(byte))
 | |
|                 elif area.type in ["DI", "DO"]:
 | |
|                     # if device.type == "PA" and device.masterOrSlave == "从站" and len(area.forceValue) == 16:
 | |
|                     byte = coilsToBytes([int(x) for x in area.forceValue], area.bytes)
 | |
|                 bytes += byte
 | |
|         else:
 | |
|             if len(bytes) % 2 != 0:
 | |
|                 bytes += struct.pack('B', 0)
 | |
|         # print(bytes)
 | |
|         # print(bytes)
 | |
|         values = struct.unpack('!' + 'H' * int(len(bytes) / 2), bytes)
 | |
|         modbusM.writeMultipleRegister(slaveId = 1, address = 0, outputValue = values)
 | |
|             # print(struct.unpack('>f', struct.pack('!HH', *values[:2])))
 | |
| 
 | |
|     def readAreas(self):
 | |
|         for index, curProDict in enumerate([self.paMasterDevices, self.paSlaveDevices, self.dpMasterDevices, self.dpSlaveDevices]):
 | |
|             match index:
 | |
|                 case 0:
 | |
|                     areaType = 'input'
 | |
|                     modbusM = self.paMasterModbus
 | |
|                 case 1:
 | |
|                     areaType = 'output'
 | |
|                     modbusM = self.paSlaveModbus
 | |
|                 case 2:
 | |
|                     areaType = 'input'
 | |
|                     modbusM = self.dpMasterModbus
 | |
|                 case 3:
 | |
|                     areaType = 'output'
 | |
|                     modbusM = self.dpSlaveModbus
 | |
|             if len(list(curProDict.values())) == 0:
 | |
|                 continue
 | |
|             inputEndAddress = max([x.inputEndAddress for x in list(curProDict.values())])
 | |
|             outputEndAddress = max([x.outputEndAddress for x in list(curProDict.values())])
 | |
|             inputAreaNums = sum([len(x.inputAreas) for x in list(curProDict.values())]) - 1
 | |
|             outputAreaNums = sum([len(x.outputAreas) for x in list(curProDict.values())]) - 1
 | |
|             bytesNums = inputEndAddress if areaType == 'input' else outputEndAddress
 | |
|             intNums = int(bytesNums / 2) if bytesNums % 2 == 0 else int(bytesNums / 2) + 1
 | |
|             if bytesNums == 0:
 | |
|                 continue
 | |
|             intValues = modbusM.readHoldingRegisters(slaveId = 1, startAddress = 0, varNums = intNums)
 | |
|             if intValues == 'error':
 | |
|                 self.connect()
 | |
|                 return
 | |
|             bytesValues = struct.pack(f"!{'H' * len(intValues)}", *intValues)
 | |
|             # print(bytesValues, intNums, bytesNums)
 | |
|                     # print(bytes)
 | |
|             for device in curProDict.values():
 | |
|                 readAreas = device.inputAreas if areaType == 'input' else device.outputAreas
 | |
|                 for area in readAreas:
 | |
|                     # print(area.startAddress, area.endAddress)
 | |
|                     if area.startAddress == 0:
 | |
|                         bytes = bytesValues[area.startAddress:area.endAddress]
 | |
|                     else:
 | |
|                         bytes = bytesValues[area.startAddress:area.endAddress]
 | |
|                     # print(area.startAddress, area.endAddress)
 | |
|                     if area.type in ['AI', 'AO']:
 | |
|                         # print(area)
 | |
|                         for i in range(0, len(bytes), 4):
 | |
|                             byte = bytes[i:i+4]
 | |
|                             if len(byte) != 4:
 | |
|                                 continue
 | |
|                             qualityByte = hex(bytes[i+4])
 | |
|                             # print(qualityByte)
 | |
|                             # print(round(struct.unpack('!f', reorderBytes(byte, area.order))[0], 4))
 | |
|                             area.currentValue[i] = round(struct.unpack('!f', reorderBytes(byte, area.order))[0], 4)
 | |
|                             area.qualityValueList = [qualityByte]
 | |
|                             # print(area.qualityValueList)
 | |
|                             # print(round(struct.unpack('!f', reorderBytes(byte, area.order))[0], 4))
 | |
|                     elif area.type in ['DI', 'DO']:
 | |
|                         if device.masterOrSlave == '主站' and device.type == 'DP':
 | |
|                             bytes = bytes
 | |
|                         else:
 | |
|                             bytes = bytes[::-1]
 | |
|                         area.currentValue = bytesToCoils(bytes)
 | |
|                     # print(area.currentValue, device.deviceName, area.startAddress,area.endAddress)
 | |
|             # print()
 | |
|     @classmethod
 | |
|     def addAreas(self, type, order, bytes, deviceName, valueName = None):
 | |
|         jsonCon = json.loads(DeviceDB.getByName(deviceName=deviceName).areaJson)
 | |
|         if jsonCon == []:
 | |
|             jsonCon = ([{
 | |
|                 "id": 0,
 | |
|                 "type": type,
 | |
|                 "order": order,
 | |
|                 "bytes": bytes,
 | |
|                 "valueName": valueName,
 | |
| 
 | |
|             }])
 | |
|         else:
 | |
|             id = jsonCon[-1]["id"] + 1
 | |
|             jsonCon.append({
 | |
|                 "id": id,
 | |
|                 "type": type,
 | |
|                 "order": order,
 | |
|                 "bytes": bytes,
 | |
|                 "valueName": valueName,
 | |
|             })
 | |
|         areaJson = json.dumps(jsonCon)
 | |
|         DeviceDB.update(areaJson=areaJson).where(DeviceDB.deviceName == deviceName).execute()
 | |
| 
 | |
|     @classmethod
 | |
|     def updataAreas(self, type, order, bytes, deviceName, valueName, index):
 | |
|         jsonCon = json.loads(DeviceDB.getByName(deviceName=deviceName).areaJson)
 | |
|         if jsonCon == []:
 | |
|             return False
 | |
|         else:
 | |
|             for area in jsonCon:
 | |
|                 if index == area["id"]:
 | |
|                     area["type"] = type
 | |
|                     area["order"] = order
 | |
|                     area["bytes"] = bytes
 | |
|                     area["valueName"] = valueName
 | |
|             areaJson = json.dumps(jsonCon)
 | |
|             DeviceDB.update(areaJson=areaJson).where(DeviceDB.deviceName == deviceName).execute()
 | |
| 
 | |
|     @classmethod
 | |
|     def getAreaID(self, deviceNames):
 | |
|         deviceName = deviceNames
 | |
|         jsonConsStr = DeviceDB.getByName(deviceName=deviceName).areaJson
 | |
|         if jsonConsStr is None:
 | |
|             return
 | |
|         else:
 | |
|             jsonCons = json.loads(jsonConsStr)
 | |
|             id = []
 | |
|             for jsonCon in jsonCons:
 | |
|                 id.append(jsonCon["id"])
 | |
|             return id
 | |
| 
 | |
| 
 | |
|     @classmethod
 | |
|     def getChannelLength(self, deviceName):
 | |
|         number = 0
 | |
|         if DeviceDB.getByName(deviceName=deviceName).areaJson is None:
 | |
|             return number
 | |
|         else:
 | |
|             numbers = json.loads(DeviceDB.getByName(deviceName=deviceName).areaJson)
 | |
|             for i in numbers:
 | |
|                 number += int(i['nums'])
 | |
|             return number
 | |
| 
 | |
|     def editDevies(self):
 | |
|         pass
 | |
| 
 | |
|     @classmethod
 | |
|     def getAllDevice(self):
 | |
|         # 查询所有设备
 | |
|         devices = DeviceDB.get_all()
 | |
|         # print(devices)
 | |
|         if devices is 'error':
 | |
|             return
 | |
|         l = []
 | |
|         for x in devices:
 | |
|             l.append([x.deviceName, x.proType, x.masterSlaveModel, x.areaJson, x.pvLowerLimit, x.pvUpperLimit, x.pvUnit])
 | |
|         return l
 | |
|     
 | |
|     @classmethod
 | |
|     def getLimitData(cls, deviceName):
 | |
|         try:
 | |
|             pvUpperLimit = DeviceDB.getByName(deviceName=deviceName).pvUpperLimit
 | |
|             pvLowerLimit = DeviceDB.getByName(deviceName=deviceName).pvLowerLimit
 | |
|             pvUnit = DeviceDB.getByName(deviceName=deviceName).pvUnit
 | |
|             l =[pvUpperLimit, pvLowerLimit, pvUnit]
 | |
|             return l
 | |
|         except Exception as e:
 | |
|             return print(e)
 |