diff --git a/UI/AreaTabWidget.py b/UI/AreaTabWidget.py index e0f1f31..19fde02 100644 --- a/UI/AreaTabWidget.py +++ b/UI/AreaTabWidget.py @@ -18,7 +18,6 @@ class AreaTabWidget(QMainWindow): self.areaTabWidget = QTabWidget(self) self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - # 设置主窗口的中心部分为 QTabWidget self.setCentralWidget(self.areaTabWidget) @@ -109,6 +108,7 @@ class AreaTabWidget(QMainWindow): def addAreaWidget(self, widgetList, loacl = True, init = False): + self.mainwindow.readVarTimer.stop() dataType = widgetList[0].currentText() # print(widgetList) order = self.dataTypeTranslate(widgetList[1].currentText()) @@ -116,7 +116,7 @@ class AreaTabWidget(QMainWindow): areaLayout = widgetList[3] deviceName = self.areaTabWidget.parent().parent().parent().parent().parent().windowTitle() widgetLists = [] - + while areaLayout.count(): item = areaLayout.takeAt(0) widget = item.widget() @@ -126,11 +126,11 @@ class AreaTabWidget(QMainWindow): if len(byteLineEdit) == 0: QMessageBox.warning(self, '警告', '请输入字节长度。') - + return else: widgetList[0].setEnabled(False) if dataType in ['AI', 'AO']: - areaLabel = QLabel(dataType + str(1) + ": " + byteLineEdit + 'Byte' ) + areaLabel = QLabel(dataType + str(1) + ": " + '字节长度: ' + byteLineEdit + ' 当前值: ' ) areaLabel2 =QLabel('0') if '主站' in deviceName and dataType == 'AI' or ('从站' in deviceName and dataType == 'AO'): @@ -157,14 +157,14 @@ class AreaTabWidget(QMainWindow): '从站' in deviceName and dataType == 'DO'): for i in range(int(channelNumber)): if i % 2 == 0: - areaLabel = QLabel(dataType + str(i + 1) + ": " + byteLineEdit + 'Byte') + areaLabel = QLabel(dataType + str(1) + ": " + '字节长度: ' + byteLineEdit + ' 当前值: ') areaLabel2 = QLabel('0') areaLayout.addWidget(areaLabel, i // 2, i % 2) areaLayout.addWidget(areaLabel2, i // 2, i % 2 + 1) widgetLists.append([areaLabel2, areaLayout, areaLabel]) else: - areaLabel = QLabel(dataType + str(i + 1) + ": " + byteLineEdit + 'Byte') + areaLabel = QLabel(dataType + str(1) + ": " + '字节长度: ' + byteLineEdit + ' 当前值: ') areaLabel2 = QLabel('0') areaLayout.addWidget(areaLabel, i // 2, i % 2 + 2) areaLayout.addWidget(areaLabel2, i // 2, i % 2 + 3) @@ -174,7 +174,7 @@ class AreaTabWidget(QMainWindow): '从站' in deviceName and dataType == 'DI'): for i in range(int(channelNumber)): if i % 2 == 0: - areaLabel = QLabel(dataType + str(i + 1) + ": " + byteLineEdit + 'Byte') + areaLabel = QLabel(dataType + str(1) + ": " + '字节长度: ' + byteLineEdit + ' 当前值: ') areaLabel2 = QLabel('0') areaLineEdit = QLineEdit('0') editbtn = QPushButton('强制') @@ -186,7 +186,7 @@ class AreaTabWidget(QMainWindow): editbtn.clicked.connect(lambda checked, btn=editbtn: self.wirteValue(btn)) widgetLists.append([areaLabel2, areaLineEdit, editbtn, areaLabel]) else: - areaLabel = QLabel(dataType + str(i + 1) + ": " + byteLineEdit + 'Byte') + areaLabel = QLabel(dataType + str(1) + ": " + '字节长度: ' + byteLineEdit + ' 当前值: ') areaLabel2 = QLabel('0') areaLineEdit = QLineEdit('0') editbtn = QPushButton('强制') @@ -215,10 +215,12 @@ class AreaTabWidget(QMainWindow): DevicesManange.updataAreas(dataType, order, byteLineEdit, deviceName, index) self.mainwindow.devicesManange.getDevice(deviceName).editArea(index = index - 1, type = dataType, order = order, bytes = int(byteLineEdit)) self.mainwindow.devicesManange.recalculateAddress() + self.mainwindow.readVarTimer.start(500) else: DevicesManange.addAreas(dataType, order, byteLineEdit, deviceName) self.mainwindow.devicesManange.getDevice(deviceName).addArea(type = dataType, bytes = int(byteLineEdit), order = order, nums = 1) self.mainwindow.devicesManange.recalculateAddress() + self.mainwindow.readVarTimer.start(500) @@ -243,8 +245,8 @@ class AreaTabWidget(QMainWindow): dataType = widgetList[-1].text()[0:2] # if dataType in ['DI', "DO"]: didoValueList.append(float(widgetList[1].text())) - - valueList.append(didoValueList) + if didoValueList: + valueList.append(didoValueList) didoValueList = [] # print(valueList) self.mainwindow.devicesManange.writeAreas(deviceName = deviceName, values = valueList) @@ -252,32 +254,33 @@ class AreaTabWidget(QMainWindow): def readValue(self): - deviceList = [] - areaIdList = [] - devices = DevicesManange.getAllDevice() - - for device in devices: - deviceName = device[0] - areas = device[3] - if areas is not None: - areas = json.loads(areas) - for area in areas: - areaId = area["id"] - areaIdList.append(areaId) - deviceList.append([deviceName, areaIdList]) - index = self.areaTabWidget.currentIndex() - - - + deviceName = self.areaTabWidget.parent().parent().parent().parent().parent().windowTitle() + curIndex = -1 + areaIndex = self.areaTabWidget.currentIndex() if len(self.widgetList) > 0: - widgetLists = self.widgetList[index] - for widgetList in widgetLists: - widgetList[0].setText('AAA') - - - - - + inputIndex = 0 + for index, widgetLists in enumerate(self.widgetList): #获取所有区域的所有的widgetlist + for widgetList in widgetLists: + #获取单个widgetlist + if isinstance(widgetList[1], QLineEdit): + pass + else: + # areaWidgets.append(widgetList) + if areaIndex == index: + curIndex = inputIndex + inputIndex += 1 + break + + if curIndex == -1: + return + else: + device = self.mainwindow.devicesManange.getDevice(deviceName) + values = device.getAreaValues(curIndex) + areaWidgets = self.widgetList[areaIndex] + for value, widgets in zip(values, areaWidgets): + widgets[0].setText(str(value)) + + if __name__ == '__main__': app = QApplication(sys.argv) diff --git a/UI/MainWindow.py b/UI/MainWindow.py index 3e8973f..0767ee4 100644 --- a/UI/MainWindow.py +++ b/UI/MainWindow.py @@ -37,7 +37,7 @@ class MainWindow(QMainWindow): self.initUI() self.initAreaWidget() - + self.states = True def initUI(self): self.toolbar = QToolBar() @@ -48,7 +48,7 @@ class MainWindow(QMainWindow): self.addDiviceBtn.setObjectName("addDiviceBtn") self.addDiviceBtn.triggered.connect(self.createDeciveWidget) - self.startProtocolBtn = QAction("开始通讯", self) + self.startProtocolBtn = QAction("开始读取", self) self.startProtocolBtn.setObjectName("startProtocolBtn") self.startProtocolBtn.triggered.connect(self.startProtocol) @@ -68,6 +68,9 @@ class MainWindow(QMainWindow): self.setWindowTitle("PROFIBUS") self.setGeometry(1000, 500, 800, 600) + self.readVarTimer = QtCore.QTimer() + self.readVarTimer.timeout.connect(self.readValues) + def deviceWidget(self, windowTitle): @@ -120,8 +123,8 @@ class MainWindow(QMainWindow): dev = self.devicesManange.getDevice(deviceName = devices[0]) dev.addArea(type = area["type"], order = area["order"], bytes = int(channelBytes), nums = 1) - self.devicesManange.recalculateAddress() areaTabWidget.initAreaTab(dataType, order, channelBytes) + self.devicesManange.recalculateAddress() def createDeciveWidget(self): dialog = DeviceDialog() @@ -130,6 +133,7 @@ class MainWindow(QMainWindow): windowTitle = deviceName + ' ' + proType + masterSlaveModel + ' ' + pvLowerLimit + '-' + pvUpperLimit + pvUnit DeviceDB().addDevice(deviceName = windowTitle, proType = proType, masterSlaveModel = masterSlaveModel, pvUpperLimit=pvUpperLimit, pvLowerLimit=pvLowerLimit, pvUnit=pvUnit) self.devicesManange.addDevice(proType = proType, masterSlaveModel = masterSlaveModel, deviceName = windowTitle) + self.devicesManange.recalculateAddress() else: return @@ -137,7 +141,19 @@ class MainWindow(QMainWindow): def startProtocol(self): - + if self.states == True: + self.readVarTimer.start(500) + self.states = False + self.startProtocolBtn.setText('停止读取') + else: + self.readVarTimer.stop() + self.states = True + self.startProtocolBtn.setText('开始读取') + def readValues(self): + # try: + self.devicesManange.readAreas() + # except Exception as e: + # print(e) for subWindow in self.subWindows: areaTabWidget = subWindow.widget().widget().centralWidget() areaTabWidget.readValue() diff --git a/model/ProjectModel/DeviceManage.py b/model/ProjectModel/DeviceManage.py index fb5623e..16de3a3 100644 --- a/model/ProjectModel/DeviceManage.py +++ b/model/ProjectModel/DeviceManage.py @@ -10,16 +10,18 @@ import struct #从站 "AI" "DI"可强制 #主站 "AO" "DO"可强制 class Device(): - inputStartAddress = None - inputEndAddress = None - outputStartAddress = None - outputEndAddress = None + inputStartAddress = 0 + inputEndAddress = 0 + outputStartAddress = 0 + outputEndAddress = 0 protocolType = None masterOrSlave = None deviceName = None def __init__(self): self.inputAreas = [] self.outputAreas = [] + self.indexDict = collections.OrderedDict() + # 有序字典 键:总区域索引 值: [类型(输入 : 0, 或输出 : 1), 该类型的第几个区域索引] def addArea(self, type, nums, bytes, order = 'ABCD'): area = Area() @@ -29,32 +31,34 @@ class Device(): 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 + 1 area.endAddress = area.startAddress + area.length 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) elif type in ["DO" , "AO"]: area.startAddress = 0 if not self.outputEndAddress else self.outputEndAddress + 1 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) - # print(self.inputAreas) - + # print(id(self), self.outputAreas) # print(area.addressList, area.startAddress, area.endAddress, self.outputAreas) def delArea(self, index, type): if type in ["DI", "AI"]: - self.inputAreas.pop(index) + self.inputAreas.pop(self.indexDict[index]) elif type in ["AO", "DO"]: - self.outputAreas.pop(index) + self.outputAreas.pop(self.indexDict[index]) # self.recalculateAddress() def recalculateAddress(self): - endAddress = 0 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 @@ -64,37 +68,37 @@ class Device(): area.startAddress = areas[index - 1].endAddress + 1 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 else: if inputOrOutput == 0: self.inputEndAddress = endAddress elif inputOrOutput == 1: self.outputEndAddress = endAddress - endAddress = 0 - + # endAddress = 0 + # print(self.deviceName, self.inputEndAddress) def editArea(self, index, type, order, bytes): if type in ["DI", "AI"]: - self.inputAreas[index].type = type - self.inputAreas[index].order = order - self.inputAreas[index].bytes = bytes + self.inputAreas[self.indexDict[index]].order = order + self.inputAreas[self.indexDict[index]].bytes = bytes elif type in ["AO", "DO"]: - self.outputAreas[index].type = type - self.outputAreas[index].order = order - self.outputAreas[index].bytes = bytes + self.outputAreas[self.indexDict[index]].order = order + self.outputAreas[self.indexDict[index]].bytes = bytes # self.recalculateAddress() def getAreaValues(self, index): - if self.masterOrSlave == "主站" + if self.masterOrSlave == "从站": return self.outputAreas[index].currentValue else: + # print(self.inputAreas, index) return self.inputAreas[index].currentValue def getLength(self, nums, bytes): length = int(nums) * int(bytes) # length = length / 2 - return length - 1 + return length @@ -176,9 +180,18 @@ class DevicesManange(): def recalculateAddress(self): for devicesDict in [self.paMasterDevices, self.paSlaveDevices, self.dpMasterDevices, self.dpSlaveDevices]: + # print(len(devicesDict)) for index, (deviceName, device) in enumerate(devicesDict.items()): - device.inputStartAddress = 0 if index == 0 else list(devicesDict.values())[index - 1].inputEndAddress + 1 - device.outputStartAddress = 0 if index == 0 else list(devicesDict.values())[index - 1].outputEndAddress + 1 + 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 + 1 + device.outputStartAddress = 0 if outputAddress == 0 else outputAddress + 1 + # print(device.inputStartAddress, device.inputEndAddress, deviceName, '输入') + # print(device.outputStartAddress, device.outputEndAddress, deviceName, 'shuchu') device.recalculateAddress() # previousDevice = device @@ -189,8 +202,10 @@ class DevicesManange(): return devicesDict[deviceName] def writeAreas(self, deviceName, 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 @@ -207,58 +222,73 @@ class DevicesManange(): areas = device.inputAreas curProDict = self.paSlaveDevices modbusM = self.paSlaveModbus + # print(values) for area, value in zip(areas, values): area.forceValue = value + if area.type in ['DI', 'DO']: + area.forceValue = value[8:] + value[:8] + for device in curProDict.values(): forceAreas = device.outputAreas if device.masterOrSlave == "主站" else device.inputAreas for area in forceAreas: - # print(area.type) + # print(area.forceValue) if area.type in ["AI", "AO"]: 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: - area.forceValue = area.forceValue[8:] + area.forceValue[:8] + # 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) 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 enumerate(devicesDict) in [self.paMasterDevices, self.paSlaveDevices, self.dpMasterDevices, self.dpSlaveDevices]: + for index, curProDict in enumerate([self.paMasterDevices, self.paSlaveDevices, self.dpMasterDevices, self.dpSlaveDevices]): match index: case 0: - areaType = 'output' + areaType = 'input' modbusM = self.paMasterModbus case 1: - areaType = 'input' - modbusM = self.paSlaverModbus - case 2: areaType = 'output' + modbusM = self.paSlaveModbus + case 2: + areaType = 'input' modbusM = self.dpMasterModbus case 3: - areaType = 'input' - modbusM = self.dpSlaverModbus - lastDevice = list(curProDict.values())[-1] - bytesNums = lastDevice.inputEndAddress if areaType == 'input' else lastDevice.outputEndAddress + 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())]) + bytesNums = inputEndAddress if areaType == 'input' else outputEndAddress intNums = int(bytesNums / 2) if bytesNums % 2 == 0 else int(bytesNums / 2) + 1 - intValues = modbusM.readHoldingRegisters(slaveId = 1, startAddress = 0, intNums) - bytesValues = struct.pack(f"!{'H' * len(intValues)}") + if bytesNums == 0: + continue + intValues = modbusM.readHoldingRegisters(slaveId = 1, startAddress = 0, varNums = intNums) + bytesValues = struct.pack(f"!{'H' * len(intValues)}", *intValues) for device in curProDict.values(): readAreas = device.inputAreas if areaType == 'input' else device.outputAreas for area in readAreas: - bytes = bytesValues[area.startAddress, area.endAddress + 1] + if area.startAddress == 0: + bytes = bytesValues[area.startAddress:area.endAddress] + else: + bytes = bytesValues[area.startAddress - 1:area.endAddress] + if area.type in ['AI', 'AO']: for i in range(0, len(bytes), 4): - byte = byte[i:i+4] + byte = bytes[i:i+4] if len(byte) != 4: - return - area.currentValue[i] = struct.unpack('!f', reorderBytes(byte)) + continue + area.currentValue[i] = round(struct.unpack('!f', reorderBytes(byte, area.order))[0], 4) elif area.type in ['DI', 'DO']: - area.currentValue = bytesToCoils(byte) + bytes = bytes[::-1] + area.currentValue = bytesToCoils(bytes) + # print(area.currentValue) @classmethod def addAreas(self, type, order, bytes, deviceName): if DeviceDB.getByName(deviceName=deviceName).areaJson is None: diff --git a/protocol/ModBus/ByteOrder.py b/protocol/ModBus/ByteOrder.py index c634766..624a933 100644 --- a/protocol/ModBus/ByteOrder.py +++ b/protocol/ModBus/ByteOrder.py @@ -91,6 +91,7 @@ def coilsToBytes(values, length): def bytesToCoils(valueByte): binaryNumber = ''.join([format(x, '08b') for x in valueByte]) values = list(reversed([int(x) for x in binaryNumber])) + # print(values) return values