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()