I'm trying to make a script to read holding registers from modbus TCP devices and insert the UINT32 decoded into MySQL :
- Read 2 registers with pymodbus
- Decode into uint32
- Insert decoded values into mySQL
- Start again every x minutes
I'm not a programmer and discovering Python.
I tried this code which seems to work but I do not understand everything, I do not know if it is the right solution to use "threading". Do you have something better to offer me?
Thank you
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)