From a5da0a61ddd0eb33d9c61e2bf4eb12fd1b01f836 Mon Sep 17 00:00:00 2001 From: Eduard Iten Date: Wed, 2 Jul 2025 17:10:11 +0200 Subject: [PATCH] Update modbus_tool.py --- software/tools/modbus_tool/modbus_tool.py | 67 ++++++++++++++++++----- 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/software/tools/modbus_tool/modbus_tool.py b/software/tools/modbus_tool/modbus_tool.py index 693b7e7..fce2423 100755 --- a/software/tools/modbus_tool/modbus_tool.py +++ b/software/tools/modbus_tool/modbus_tool.py @@ -54,33 +54,74 @@ def format_uptime(seconds): def poll_status(slave_id, interval): global status_data + reconnect_attempts = 0 + max_reconnect_attempts = 5 + reconnect_delay = 1 # seconds + while not stop_event.is_set(): - if update_status["running"]: time.sleep(interval); continue - new_data = {"error": None} + if update_status["running"]: + time.sleep(interval) + continue + + new_data = {} try: + if not client.is_connected(): + reconnect_attempts += 1 + if reconnect_attempts >= max_reconnect_attempts: + new_data["error"] = f"Failed to reconnect after {max_reconnect_attempts} attempts. Exiting." + stop_event.set() + break + + # Attempt to connect + if client.connect(): + reconnect_attempts = 0 + new_data["error"] = None # Clear error on successful reconnect + else: + new_data["error"] = f"Connection lost. Attempting to reconnect ({reconnect_attempts}/{max_reconnect_attempts})..." + time.sleep(reconnect_delay) + continue + + # If connected, try to read data ir_valve = client.read_input_registers(REG_INPUT_VALVE_STATE_MOVEMENT, count=2, slave=slave_id) ir_dig = client.read_input_registers(REG_INPUT_DIGITAL_INPUTS_STATE, count=2, slave=slave_id) ir_sys = client.read_input_registers(REG_INPUT_FIRMWARE_VERSION_MAJOR_MINOR, count=5, slave=slave_id) hr_valve = client.read_holding_registers(REG_HOLDING_MAX_OPENING_TIME_S, count=2, slave=slave_id) hr_dig = client.read_holding_registers(REG_HOLDING_DIGITAL_OUTPUTS_STATE, count=1, slave=slave_id) hr_sys = client.read_holding_registers(REG_HOLDING_WATCHDOG_TIMEOUT_S, count=1, slave=slave_id) + for res in [ir_valve, ir_dig, ir_sys, hr_valve, hr_dig, hr_sys]: - if res.isError(): raise ModbusException(str(res)) + if res.isError(): + raise ModbusException(str(res)) valve_state_raw = ir_valve.registers[0] - movement_map = {0: "Idle", 1: "Opening", 2: "Closing", 3: "Error"}; state_map = {0: "Closed", 1: "Open"} - new_data["movement"] = movement_map.get(valve_state_raw >> 8, 'Unknown'); new_data["state"] = state_map.get(valve_state_raw & 0xFF, 'Unknown') - new_data["motor_current"] = f"{ir_valve.registers[1]} mA"; new_data["open_time"] = f"{hr_valve.registers[0]}s"; new_data["close_time"] = f"{hr_valve.registers[1]}s" - new_data["digital_inputs"] = f"0x{ir_dig.registers[0]:04X}"; new_data["button_events"] = f"0x{ir_dig.registers[1]:04X}"; new_data["digital_outputs"] = f"0x{hr_dig.registers[0]:04X}" + movement_map = {0: "Idle", 1: "Opening", 2: "Closing", 3: "Error"} + state_map = {0: "Closed", 1: "Open"} + new_data["movement"] = movement_map.get(valve_state_raw >> 8, 'Unknown') + new_data["state"] = state_map.get(valve_state_raw & 0xFF, 'Unknown') + new_data["motor_current"] = f"{ir_valve.registers[1]} mA" + new_data["open_time"] = f"{hr_valve.registers[0]}s" + new_data["close_time"] = f"{hr_valve.registers[1]}s" + new_data["digital_inputs"] = f"0x{ir_dig.registers[0]:04X}" + new_data["button_events"] = f"0x{ir_dig.registers[1]:04X}" + new_data["digital_outputs"] = f"0x{hr_dig.registers[0]:04X}" - fw_major = ir_sys.registers[0] >> 8; fw_minor = ir_sys.registers[0] & 0xFF; fw_patch = ir_sys.registers[1] + fw_major = ir_sys.registers[0] >> 8 + fw_minor = ir_sys.registers[0] & 0xFF + fw_patch = ir_sys.registers[1] uptime_seconds = (ir_sys.registers[4] << 16) | ir_sys.registers[3] - new_data["firmware"] = f"v{fw_major}.{fw_minor}.{fw_patch}"; new_data["device_status"] = "OK" if ir_sys.registers[2] == 0 else "ERROR" - new_data["uptime"] = format_uptime(uptime_seconds); new_data["watchdog"] = f"{hr_sys.registers[0]}s" + new_data["firmware"] = f"v{fw_major}.{fw_minor}.{fw_patch}" + new_data["device_status"] = "OK" if ir_sys.registers[2] == 0 else "ERROR" + new_data["uptime"] = format_uptime(uptime_seconds) + new_data["watchdog"] = f"{hr_sys.registers[0]}s" + new_data["error"] = None # Clear any previous error on successful read + reconnect_attempts = 0 # Reset attempts on successful communication except Exception as e: - new_data["error"] = f"Error: {e}" - with status_lock: status_data = new_data - time.sleep(interval) + new_data["error"] = f"Communication Error: {e}. Closing connection." + client.close() # Close connection to force reconnect attempt in next loop + finally: + with status_lock: + status_data = new_data + time.sleep(interval) def firmware_update_thread(slave_id, filepath): global update_status