파이썬 Modbus TCP Poll [GUI]
Mac OS용 무료 Modbus TCP/IP Poll을 찾는 것 보다는 직접 만드는게 더 빠를 것 같아서
일단은 Holding Register만 읽을 수 있는 Modbus TCP Poll을 만들어 봤습니다.
import sys
from pyModbusTCP.client import ModbusClient
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QInputDialog, QLabel, QComboBox, QLineEdit, QPushButton, QSpinBox, QWidget
from time import sleep
from pyModbusTCP.utils import get_bits_from_int
class MyApp(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# 윈도우 셋팅
self.setWindowTitle("Modbus TCP/IP Application")
self.move(0, 0)
self.setGeometry(0, 0, 560, 900)
####### 첫 번째 줄 #####
# 라벨 1 : Modbus Mode
self.label_1 = QLabel('Modbus Mode', self)
self.label_1.move(10, 10)
# 콤보박스 : TCP/RTU 선택
cb_mode = QComboBox(self)
cb_mode.addItem('TCP')
cb_mode.addItem('RTU')
cb_mode.move(100, 4)
cb_mode.activated[str].connect(self.onActivated)
# 라벨 2 : Unit ID
self.label_2 = QLabel('Unit ID', self)
self.label_2.move(180, 10)
# 스핀박스 1 : Unit ID 선택
self.spinbox_1 = QSpinBox(self)
self.spinbox_1.move(230, 8)
self.spinbox_1.setRange(1, 255)
self.spinbox_1.setSingleStep(1)
self.spinbox_1.valueChanged.connect(self.value_changed_1)
# 라벨 3 : Scan Rate (ms)
self.label_3 = QLabel('Scan Rate (ms)', self)
self.label_3.move(290, 10)
# 스핀박스 2 : Scan Rate (ms) 선택
self.spinbox_2 = QSpinBox(self)
self.spinbox_2.move(385, 8)
self.spinbox_2.setRange(1000, 10000)
self.spinbox_2.setSingleStep(500)
# 푸쉬 버튼 1 : IP 셋팅 버튼
self.btn1 = QPushButton('IP Setting', self)
self.btn1.setCheckable(True)
self.btn1.toggle()
self.btn1.move(450, 4)
self.btn1.clicked.connect(self.showDialog)
#####################################
####### 두 번째 줄 ##########
# 라벨 4 : Function Code
self.label_4 = QLabel('Function Code', self)
self.label_4.move(10, 40)
# 콤보박스 : Function Code 선택
cb_code = QComboBox(self)
cb_code.addItem('[ 0x01 ] Read Coils')
cb_code.addItem('[ 0x02 ] Read Discrete Inputs')
cb_code.addItem('[ 0x03 ] Read Holding Registers')
cb_code.addItem('[ 0x04 ] Read Input Registers')
cb_code.addItem('[ 0x05 ] Write Single Coil')
cb_code.addItem('[ 0x06 ] Write Single Register')
cb_code.addItem('[ 0x0f ] Write Multiple Coils')
cb_code.addItem('[ 0x10 ] Write Multiple Registers')
cb_code.setCurrentIndex(2)
cb_code.move(100, 34)
# 라벨 5 : Start Address
self.label_5 = QLabel('Start Address', self)
self.label_5.move(345, 40)
# 스핀박스 3 : Start Address 선택
self.spinbox_3 = QSpinBox(self)
self.spinbox_3.move(430, 38)
self.spinbox_3.setRange(0, 65535)
self.spinbox_3.setSingleStep(1)
self.spinbox_3.valueChanged.connect(self.value_changed_3)
# 콤보박스 : Address Type 선택
cb_type = QComboBox(self)
cb_type.addItem('Hex')
cb_type.addItem('Dec')
cb_type.setCurrentIndex(1)
cb_type.move(490, 34)
#########################################################
###### 세 번째 줄 ###################
# 라벨 6 : Number of Registers
self.label_6 = QLabel('Number of Registers', self)
self.label_6.move(10, 70)
# 스핀박스 4 : Number of Registers 선택
self.spinbox_4 = QSpinBox(self)
self.spinbox_4.move(140, 68)
self.spinbox_4.setRange(1, 125)
self.spinbox_4.setSingleStep(1)
self.temp_4 = int(self.spinbox_4.value())
self.spinbox_4.valueChanged.connect(self.value_changed_4)
# 라벨 7 : Data Format
self.label_7 = QLabel('Data Format', self)
self.label_7.move(200, 70)
# 콤보박스 : Data Format 선택
cb_format = QComboBox(self)
cb_format.addItem('Bin')
cb_format.addItem('Dec')
cb_format.addItem('Hex')
cb_format.addItem('Float')
cb_format.setCurrentIndex(1)
cb_format.move(280, 64)
##############################################
######### 네 번째 줄 ###############
# 라인에디터 : 1개 Enable, 124개 Disable로 생성
for i in range(1, 11):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-20+(i*50), 100)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(11, 21):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-520+(i*50), 150)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(21, 31):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-1020+(i*50), 200)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(31, 41):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-1520+(i*50), 250)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(41, 51):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-2020+(i*50), 300)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(51, 61):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-2520+(i*50), 350)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(61, 71):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-3020+(i*50), 400)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(71, 81):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-3520+(i*50), 450)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(81, 91):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-4020+(i*50), 500)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(91, 101):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-4520+(i*50), 550)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(101, 111):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-5020+(i*50), 600)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(111, 121):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-5520+(i*50), 650)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(121, 126):
globals()['tb_{}'.format(i)] = QLineEdit(self)
globals()['tb_{}'.format(i)].move(-6020+(i*50), 700)
globals()['tb_{}'.format(i)].resize(50, 50)
#print('tb_{}'.format(i))
for i in range(2, 126):
globals()['tb_{}'.format(i)].setEnabled(False)
# 푸쉬 버튼 2 : 1회 read 버튼
self.btn2 = QPushButton('read/write', self)
self.btn2.move(350, 70)
self.btn2.clicked.connect(self.readModbus)
###########################################
self.label_8 = QLabel('Slave IP :', self)
self.label_8.move(10, 770)
self.ipLabel = QLabel('000.000.000.000', self)
self.ipLabel.move(70, 770)
self.label_9 = QLabel('TCP Port :', self)
self.label_9.move(200, 770)
self.portLabel = QLabel('00000', self)
self.portLabel.move(265, 770)
self.show()
def showDialog(self):
ipAddress, okPressed = QInputDialog.getText(self, 'Modbus TCP Settings', 'Slave IP')
if okPressed:
self.ipLabel.setText(ipAddress)
global G_ipAddress
G_ipAddress = ipAddress
port, okPressed = QInputDialog.getText(self, 'Modbus TCP Settings', 'TCP Port')
if okPressed:
self.portLabel.setText(port)
global G_port
G_port = port
def onActivated(self, text):
self.label_1.setText(text)
self.label_1.adjstSize()
def value_changed_1(self):
unit_id = self.spinbox_1.value()
return unit_id
def value_changed_3(self):
val_3 = int(self.spinbox_3.value())
return val_3
def value_changed_4(self):
val_4 = int(self.spinbox_4.value())
global G_nb
G_nb = val_4
if val_4 >= self.temp_4:
self.temp_4 = val_4
for i in range(2, val_4 + 1):
globals()['tb_{}'.format(i)].setEnabled(True)
else:
self.temp_4 = val_4
globals()['tb_{}'.format(val_4+1)].setEnabled(False)
def readModbus(self):
read_list = [0]
unit_id = self.value_changed_1()
start = self.value_changed_3()
client = ModbusClient(host=G_ipAddress, port=G_port, unit_id=unit_id, debug=False)
client.open()
if client.is_open():
read_list = client.read_holding_registers(reg_addr=start, reg_nb=G_nb)
for i in range(1, G_nb + 1):
read_data = str(read_list[i-1])
globals()['tb_{}'.format(i)].setText(read_data)
globals()['tb_{}'.format(i)].setAlignment(QtCore.Qt.AlignRight)
client.close()
else:
print("fail")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyApp()
sys.exit(app.exec_())
이상입니다.
'Programming > Python' 카테고리의 다른 글
파이썬 1부터 45까지의 숫자로 만들 수 있는 모든 6개 숫자 조합 (0) | 2024.01.16 |
---|---|
파이썬 윈도우10 pip Fatal error in launcher: Unable to create process using ????? (0) | 2022.07.20 |
파이썬 py pyw 차이 (0) | 2021.06.03 |
파이썬 네이버 상한가 찾기 GUI [심화] (0) | 2021.05.31 |
티스토리 api access_token 받아오기 (0) | 2021.05.07 |