@@ -40,58 +40,79 @@ def find_serial_ports() -> List[str]:
4040 logger .info (f"Found { len (available_ports )} serial ports: { available_ports } " )
4141 return available_ports
4242
43- def test_modbus_port (port : str , baudrate : int = 9600 , timeout : float = 0.5 ) -> bool :
43+ def test_modbus_port (port : str , baudrate : int = 9600 , timeout : float = 0.5 , unit_id : int = 1 ) -> bool :
4444 """
4545 Test if a serial port has a Modbus device connected
4646
4747 Args:
4848 port: Serial port path to test
4949 baudrate: Baud rate to test
5050 timeout: Timeout in seconds
51+ unit_id: Modbus unit ID to test (default: 1)
5152
5253 Returns:
5354 bool: True if a Modbus device is detected
5455 """
56+ from .protocol import build_read_request , parse_response
57+
5558 try :
5659 # Try to open the port
5760 with serial .Serial (port = port , baudrate = baudrate , timeout = timeout ) as ser :
5861 # Clear any pending data
5962 ser .reset_input_buffer ()
6063 ser .reset_output_buffer ()
6164
62- # Send a Modbus request to read device ID (unit 1 )
63- # This is a standard Modbus request that most devices should respond to
64- request = bytes ([ 0x01 , 0x03 , 0x00 , 0x00 , 0x00 , 0x01 , 0x84 , 0x0A ] )
65+ # Test 1: Try reading holding registers (function code 0x03 )
66+ # This is a common operation that most Modbus devices support
67+ request = build_read_request ( unit_id , 0x03 , 0x0000 , 1 )
6568 ser .write (request )
6669
6770 # Wait for response
6871 time .sleep (0.1 )
6972
70- # Check if we got any response
7173 if ser .in_waiting > 0 :
7274 response = ser .read (ser .in_waiting )
73- logger .debug (f"Got response from { port } : { response .hex ()} " )
75+ logger .debug (f"Got response from { port } (FC03) : { response .hex ()} " )
7476
75- # Even if the response is an exception , it means a Modbus device is present
76- if len (response ) >= 3 and response [ 0 ] == 0x01 :
77+ # If we got any response , it's likely a Modbus device
78+ if len (response ) >= 5 : # Minimum valid Modbus RTU response length
7779 return True
7880
79- # Try a broadcast message to read device address
80- request = bytes ([0x00 , 0x03 , 0x40 , 0x00 , 0x00 , 0x01 , 0x90 , 0x1B ])
81+ # Test 2: Try reading coils (function code 0x01)
82+ ser .reset_input_buffer ()
83+ request = build_read_request (unit_id , 0x01 , 0x0000 , 1 )
8184 ser .write (request )
8285
8386 # Wait for response
84- time .sleep (0.2 )
87+ time .sleep (0.1 )
8588
86- # Check if we got any response
8789 if ser .in_waiting > 0 :
8890 response = ser .read (ser .in_waiting )
89- logger .debug (f"Got broadcast response from { port } : { response .hex ()} " )
90- return True
91+ logger .debug (f"Got response from { port } (FC01): { response .hex ()} " )
92+
93+ # If we got any response, it's likely a Modbus device
94+ if len (response ) >= 5 : # Minimum valid Modbus RTU response length
95+ return True
96+
97+ # Test 3: Try reading input registers (function code 0x04)
98+ ser .reset_input_buffer ()
99+ request = build_read_request (unit_id , 0x04 , 0x0000 , 1 )
100+ ser .write (request )
101+
102+ # Wait for response
103+ time .sleep (0.1 )
104+
105+ if ser .in_waiting > 0 :
106+ response = ser .read (ser .in_waiting )
107+ logger .debug (f"Got response from { port } (FC04): { response .hex ()} " )
108+
109+ # If we got any response, it's likely a Modbus device
110+ if len (response ) >= 5 : # Minimum valid Modbus RTU response length
111+ return True
91112
92113 return False
93114 except Exception as e :
94- logger .debug (f"Error testing { port } : { e } " )
115+ logger .debug (f"Error testing { port } at { baudrate } baud : { str ( e ) } " )
95116 return False
96117
97118def scan_for_devices (ports : List [str ] = None ,
@@ -102,31 +123,35 @@ def scan_for_devices(ports: List[str] = None,
102123
103124 Args:
104125 ports: List of ports to scan (default: auto-detect)
105- baudrates: List of baudrates to try (default: [9600, 115200, 19200] )
106- unit_ids: List of unit IDs to try (default: [1, 2, 3] )
126+ baudrates: List of baudrates to try (default: from config.BAUDRATES )
127+ unit_ids: List of unit IDs to try (default: from config.AUTO_DETECT_UNIT_IDS )
107128
108129 Returns:
109130 List[Dict[str, Any]]: List of detected devices with configuration
110131 """
132+ from .config import BAUDRATES as DEFAULT_BAUDRATES , AUTO_DETECT_UNIT_IDS
133+
111134 if ports is None :
112135 ports = find_serial_ports ()
113136
114137 if baudrates is None :
115- baudrates = [ 9600 , 115200 , 19200 , 4800 , 38400 , 57600 ]
138+ baudrates = DEFAULT_BAUDRATES
116139
117140 if unit_ids is None :
118- unit_ids = [ 1 , 2 , 3 ]
141+ unit_ids = AUTO_DETECT_UNIT_IDS
119142
120143 detected_devices = []
121144
122145 for port in ports :
123146 for baudrate in baudrates :
124- if test_modbus_port (port , baudrate ):
125- device_info = {
126- 'port' : port ,
127- 'baudrate' : baudrate ,
128- 'unit_ids' : []
129- }
147+ for unit_id in unit_ids :
148+ if test_modbus_port (port , baudrate , unit_id = unit_id ):
149+ device_info = {
150+ 'port' : port ,
151+ 'baudrate' : baudrate ,
152+ 'unit_id' : unit_id ,
153+ 'unit_ids' : [unit_id ] # For backward compatibility
154+ }
130155
131156 # Try to determine unit IDs
132157 try :
0 commit comments