我正在尝试编写一个脚本来从 modbus TCP 设备读取保持寄存器并将解码的 UINT32 插入 MySQL :
- 使用 pymodbus 读取 2 个寄存器
- 解码成 uint32
- 将解码后的值插入 mySQL
- 每 x 分钟重新开始
我不是程序员,也不是发现 Python。
我尝试了这个似乎可以工作的代码,但我不明白所有内容,我不知道它是否是使用“线程”的正确解决方案。你有更好的给我吗?
谢谢
import time
import pymysql.cursors
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
from threading import Thread, Lock
from pyModbusTCP.client import ModbusClient
# connect database
#sqlconnection = pymysql.connect(host='127.0.0.1',
# user='root',
# password='',
# database='database',
# charset='utf8mb4',
# cursorclass=pymysql.cursors.DictCursor)
# read devices informations (ID, IP, Port, Register address)
#with sqlconnection:
# with sqlconnection.cursor() as cursor:
# sql = "SELECT `dev_id`, H0.hw_address, H0.hw_port FROM `devicestatus` LEFT JOIN `hardware` H0 ON H0.hw_id = devicestatus.dev_hw_id WHERE H0.hw_enabled = 1 AND devicestatus.dev_used = 1 ORDER BY H0.hw_address, dev_name"
# cursor.execute(sql,)
# result = cursor.fetchall()
# sample of result
result = [{'dev_id': 7, 'hw_address': '127.0.0.1', 'hw_port': 502}, {'dev_id': 8, 'hw_address': '127.0.0.1', 'hw_port': 502}, {'dev_id': 9, 'hw_address': '127.0.0.1', 'hw_port': 502}]
# set global variables
regs = []
sf_value = 0
# init a thread lock
regs_lock = Lock()
# modbus polling thread
def polling_thread():
global regs
# polling loop
while True:
REGISTER_ADDRESS = 98 #First device is at address %MD100 (in Schneider M221 simulator), i dont' understand why i need to do -2
# For each dictionary of the list, "extract" each value of element : information useful to launch Modbus requests, one per device.
for val in result:
# set modbusTCP variables :
DEV_ID = val['dev_id']
SERVER_HOST = val['hw_address']
SERVER_PORT = val['hw_port']
SERVER_ID = 1
REGISTER_ADDRESS = REGISTER_ADDRESS + 2 # to read %MD100 %MD102 %MD104 ...
REGISTER_COUNT = 2
print("Target :", SERVER_HOST, SERVER_PORT, REGISTER_ADDRESS)
client = ModbusClient(host=SERVER_HOST, port=int(SERVER_PORT), unit_id=int(SERVER_ID), auto_open=True, auto_close=True, timeout=2)
# keep TCP open
if not client.is_open():
client.open()
# do modbus reading on socket
reg_read = client.read_holding_registers(REGISTER_ADDRESS, REGISTER_COUNT)
# if read is ok, store result in regs (with thread lock synchronization)
if reg_read:
# decode the 2 registers into a 32 bit integer
decoder = BinaryPayloadDecoder.fromRegisters(reg_read, byteorder=Endian.Big, wordorder=Endian.Little)
sf_value = decoder.decode_32bit_int()
with regs_lock:
regs = sf_value
print(regs)
# To do : insert each data into sql table
#with sqlconnection:
#with sqlconnection.cursor() as cursor:
# Create a new record
#sql = "INSERT INTO ...
# x sec before next polling
time.sleep(2)
# start polling thread
tp = Thread(target=polling_thread)
# set daemon: polling thread will exit if main thread exit
tp.daemon = True
tp.start()
# display loop (in main thread)
while True:
# print regs (with thread lock synchronization)
with regs_lock:
#print(regs)
print("What is this part ? everything is done in the polling_thread")
# x sec before next print
time.sleep(2)