122 lines
3.7 KiB
Python
122 lines
3.7 KiB
Python
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
|
|
from pymodbus.exceptions import ModbusIOException
|
|
from time import sleep
|
|
import threading
|
|
|
|
|
|
MODBUS_CLIENT = '172.16.2.157'
|
|
MODBUS_REFRESH_PERIOD = 0.25
|
|
|
|
|
|
coils = []
|
|
shadowCoils = []
|
|
|
|
discreteInputs = []
|
|
shadowDiscreteInputs = []
|
|
|
|
analogInputs = []
|
|
shadowAnalogInputs = []
|
|
|
|
changeCondition = threading.Condition()
|
|
|
|
|
|
def modbusHandler():
|
|
global coils, shadowCoils, discreteInputs, shadowDiscreteInputs, analogInputs, shadowAnalogInputs
|
|
|
|
|
|
client = ModbusClient(MODBUS_CLIENT)
|
|
|
|
try:
|
|
client.connect()
|
|
|
|
processImage = client.read_holding_registers(0x1010, 4)
|
|
if isinstance(processImage, ModbusIOException):
|
|
raise Exception(processImage)
|
|
|
|
if len(processImage.registers) != 4:
|
|
raise Exception("Unexpected number of registers in process image ({})".format(len(processImage.registers)))
|
|
|
|
(analogOutputBits, analogInputBits, digitalOutputBits, digitalInputBits) = processImage.registers
|
|
print(f"AO: {analogOutputBits}, AI: {analogInputBits}, DO: {digitalOutputBits}, DI: {digitalInputBits}")
|
|
|
|
shadowAnalogInputs = [ -1 ] * (analogInputBits // 8)
|
|
shadowDiscreteInputs = [ -1 ] * digitalInputBits
|
|
|
|
reg = client.read_coils(0, digitalOutputBits)
|
|
if isinstance(reg, ModbusIOException):
|
|
raise Exception(reg)
|
|
coils = reg.bits
|
|
shadowCoils = coils
|
|
|
|
|
|
while True:
|
|
try:
|
|
if not client.is_socket_open():
|
|
client.connect()
|
|
|
|
reg = client.read_input_registers(0, analogInputBits // 8)
|
|
if isinstance(reg, ModbusIOException):
|
|
raise Exception(reg)
|
|
analogInputs = reg.registers
|
|
|
|
reg = client.read_discrete_inputs(0, digitalInputBits)
|
|
if isinstance(reg, ModbusIOException):
|
|
raise Exception(reg)
|
|
discreteInputs = reg.bits
|
|
|
|
if (discreteInputs != shadowDiscreteInputs) or (analogInputs != shadowAnalogInputs):
|
|
with changeCondition:
|
|
changeCondition.notify()
|
|
|
|
if coils != shadowCoils:
|
|
reg = client.write_coils(0, shadowCoils)
|
|
if isinstance(reg, ModbusIOException):
|
|
raise Exception(reg)
|
|
coils = shadowCoils
|
|
|
|
except Exception as e:
|
|
print("Exception in inner modbus handler loop: {}".format(e))
|
|
client.close()
|
|
finally:
|
|
sleep(MODBUS_REFRESH_PERIOD)
|
|
|
|
except Exception as e:
|
|
print("Exception in modbus handler: {}".format(e))
|
|
finally:
|
|
client.close()
|
|
|
|
|
|
|
|
def publisher():
|
|
global coils, shadowCoils, discreteInputs, shadowDiscreteInputs, analogInputs, shadowAnalogInputs
|
|
|
|
while True:
|
|
with changeCondition:
|
|
changeCondition.wait()
|
|
|
|
if discreteInputs != shadowDiscreteInputs:
|
|
for i in range(len(shadowDiscreteInputs)):
|
|
if discreteInputs[i] != shadowDiscreteInputs[i]:
|
|
print("di changed: {}, {}".format(i, discreteInputs[i]))
|
|
shadowDiscreteInputs = discreteInputs
|
|
|
|
if analogInputs != shadowAnalogInputs:
|
|
for i in range(len(shadowAnalogInputs)):
|
|
if analogInputs[i] != shadowAnalogInputs[i]:
|
|
print("ai changed: {}, {}".format(i, analogInputs[i]))
|
|
shadowAnalogInputs = analogInputs
|
|
|
|
|
|
|
|
|
|
modbusThread = threading.Thread(target=modbusHandler)
|
|
publisherThread = threading.Thread(target=publisher)
|
|
|
|
modbusThread.start()
|
|
publisherThread.start()
|
|
|
|
|
|
|
|
|
|
|