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.

427 lines
18 KiB
Python

import collections
import json
from utils.DBModels.DeviceModels import DeviceDB
from model.ProjectModel.AreaManage import Area
import numpy as np
from protocol.ModBus.ByteOrder import *
from protocol.ModBus.TCPMaster import *
import struct
import time
#从站 "AI" "DI"可强制
#主站 "AO" "DO"可强制
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'):
area = Area()
bytes = int(bytes)
area.type = type
area.order = order
area.bytes = bytes
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())] = 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())] = 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])
elif type in ["AO", "DO"]:
self.outputAreas.pop(self.indexDict[index])
self.indexDict.pop(index)
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
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):
# 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
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)
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
# print(round(struct.unpack('!f', reorderBytes(byte, area.order))[0], 4))
area.currentValue[i] = round(struct.unpack('!f', reorderBytes(byte, area.order))[0], 4)
# 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):
jsonCon = json.loads(DeviceDB.getByName(deviceName=deviceName).areaJson)
if jsonCon == []:
jsonCon = ([{
"id": 0,
"type": type,
"order": order,
"bytes": bytes,
}])
else:
id = jsonCon[-1]["id"] + 1
jsonCon.append({
"id": id,
"type": type,
"order": order,
"bytes": bytes,
})
areaJson = json.dumps(jsonCon)
DeviceDB.update(areaJson=areaJson).where(DeviceDB.deviceName == deviceName).execute()
@classmethod
def updataAreas(self, type, order, bytes, deviceName, 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
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()
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)