0
# Device Discovery and Information
1
2
Network device discovery and device property retrieval capabilities for system diagnostics, configuration, and network management. These functions enable automatic detection of Ethernet I/P devices and detailed device information gathering.
3
4
## Capabilities
5
6
### Network Device Discovery
7
8
Discover all Ethernet I/P devices on the local network using broadcast discovery packets.
9
10
```python { .api }
11
def Discover():
12
"""
13
Discover Ethernet I/P devices on the network.
14
15
Note: Not available on MicroPython due to socket limitations.
16
17
Returns:
18
Response: Object containing list of discovered devices
19
- Value: List of Device objects with device information
20
- Status: "Success" or error description
21
"""
22
```
23
24
**Usage Examples:**
25
26
```python
27
from pylogix import PLC
28
29
with PLC() as comm:
30
# Discover all devices on the network
31
response = comm.Discover()
32
if response.Status == 'Success':
33
devices = response.Value
34
print(f"Discovered {len(devices)} devices:")
35
36
for device in devices:
37
print(f"\nDevice: {device.IPAddress}")
38
print(f" Product: {device.ProductName}")
39
print(f" Vendor: {device.Vendor}")
40
print(f" Device Type: {device.DeviceType}")
41
print(f" Product Code: {device.ProductCode}")
42
print(f" Revision: {device.Revision}")
43
print(f" Serial Number: {device.SerialNumber}")
44
print(f" Status: 0x{device.Status:04x}")
45
else:
46
print(f"Discovery failed: {response.Status}")
47
```
48
49
### Device Property Retrieval
50
51
Get detailed properties of the currently connected device.
52
53
```python { .api }
54
def GetDeviceProperties():
55
"""
56
Get properties of the device at the specified IP address.
57
58
Returns:
59
Response: Object containing device information
60
- Value: Device object with detailed properties
61
- Status: "Success" or error description
62
"""
63
```
64
65
**Usage Examples:**
66
67
```python
68
with PLC() as comm:
69
comm.IPAddress = '192.168.1.100'
70
71
# Get properties of the connected device
72
response = comm.GetDeviceProperties()
73
if response.Status == 'Success':
74
device = response.Value
75
76
print(f"Device Properties for {device.IPAddress}:")
77
print(f" Product Name: {device.ProductName}")
78
print(f" Vendor: {device.Vendor} (ID: {device.VendorID})")
79
print(f" Device Type: {device.DeviceType} (ID: {device.DeviceID})")
80
print(f" Product Code: {device.ProductCode}")
81
print(f" Revision: {device.Revision}")
82
print(f" Serial Number: {device.SerialNumber}")
83
print(f" Encapsulation Version: {device.EncapsulationVersion}")
84
print(f" Status: 0x{device.Status:04x}")
85
print(f" State: {device.State}")
86
else:
87
print(f"Failed to get device properties: {response.Status}")
88
```
89
90
### Module Property Retrieval
91
92
Get properties of modules installed in specific slots of a chassis-based system.
93
94
```python { .api }
95
def GetModuleProperties(slot):
96
"""
97
Get properties of a module in a specific slot.
98
99
Args:
100
slot (int): Slot number to query (0-based)
101
102
Returns:
103
Response: Object containing module information
104
- Value: Device object representing the module
105
- Status: "Success" or error description
106
"""
107
```
108
109
**Usage Examples:**
110
111
```python
112
with PLC() as comm:
113
comm.IPAddress = '192.168.1.100'
114
115
# Query modules in different slots
116
for slot in range(8): # Check slots 0-7
117
response = comm.GetModuleProperties(slot)
118
if response.Status == 'Success':
119
module = response.Value
120
if module.ProductName: # Module present
121
print(f"Slot {slot}: {module.ProductName}")
122
print(f" Type: {module.DeviceType}")
123
print(f" Vendor: {module.Vendor}")
124
print(f" Product Code: {module.ProductCode}")
125
print(f" Revision: {module.Revision}")
126
print(f" Serial: {module.SerialNumber}")
127
print()
128
else:
129
print(f"Slot {slot}: Empty or error - {response.Status}")
130
```
131
132
### Comprehensive Network Scan
133
134
Perform a complete network scan to map all available devices and their capabilities.
135
136
```python
137
def network_scan_and_analysis():
138
"""Perform comprehensive network device analysis."""
139
140
with PLC() as comm:
141
# Discover all devices
142
discovery_response = comm.Discover()
143
if discovery_response.Status != 'Success':
144
print(f"Network discovery failed: {discovery_response.Status}")
145
return None
146
147
devices = discovery_response.Value
148
print(f"Network Scan Results: {len(devices)} devices found\n")
149
150
device_analysis = []
151
152
for i, device in enumerate(devices, 1):
153
print(f"Device {i}: {device.IPAddress}")
154
print(f" Product: {device.ProductName}")
155
print(f" Vendor: {device.Vendor}")
156
print(f" Type: {device.DeviceType}")
157
print(f" Revision: {device.Revision}")
158
159
# Try to connect and get detailed properties
160
comm.IPAddress = device.IPAddress
161
detailed_response = comm.GetDeviceProperties()
162
163
device_info = {
164
'ip_address': device.IPAddress,
165
'product_name': device.ProductName,
166
'vendor': device.Vendor,
167
'device_type': device.DeviceType,
168
'product_code': device.ProductCode,
169
'revision': device.Revision,
170
'serial_number': device.SerialNumber,
171
'can_connect': detailed_response.Status == 'Success',
172
'is_plc': False,
173
'slot_count': 0,
174
'modules': []
175
}
176
177
# Check if this is a PLC by looking for common PLC device types
178
plc_types = ['Programmable Logic Controller', 'ControlLogix', 'CompactLogix']
179
if any(plc_type.lower() in device.DeviceType.lower() for plc_type in plc_types):
180
device_info['is_plc'] = True
181
print(" -> Identified as PLC")
182
183
# If it's a PLC, check for modules in slots
184
if detailed_response.Status == 'Success':
185
modules_found = 0
186
for slot in range(16): # Check up to 16 slots
187
module_response = comm.GetModuleProperties(slot)
188
if module_response.Status == 'Success':
189
module = module_response.Value
190
if module.ProductName:
191
modules_found += 1
192
device_info['modules'].append({
193
'slot': slot,
194
'product_name': module.ProductName,
195
'device_type': module.DeviceType,
196
'product_code': module.ProductCode
197
})
198
print(f" Slot {slot}: {module.ProductName}")
199
200
device_info['slot_count'] = modules_found
201
if modules_found > 0:
202
print(f" -> Found {modules_found} modules")
203
204
device_analysis.append(device_info)
205
print()
206
207
# Summary analysis
208
print("=== Network Analysis Summary ===")
209
plc_count = sum(1 for d in device_analysis if d['is_plc'])
210
connectable_count = sum(1 for d in device_analysis if d['can_connect'])
211
212
print(f"Total devices: {len(device_analysis)}")
213
print(f"PLCs identified: {plc_count}")
214
print(f"Connectable devices: {connectable_count}")
215
216
if plc_count > 0:
217
print("\nPLC Details:")
218
for device in device_analysis:
219
if device['is_plc']:
220
print(f" {device['ip_address']}: {device['product_name']}")
221
if device['modules']:
222
print(f" Modules: {len(device['modules'])}")
223
224
return device_analysis
225
226
# Usage
227
network_devices = network_scan_and_analysis()
228
```
229
230
### Device Information Analysis
231
232
Analyze device information to understand network topology and capabilities.
233
234
```python
235
def analyze_device_capabilities(device):
236
"""Analyze device capabilities based on properties."""
237
238
capabilities = {
239
'is_plc': False,
240
'is_io_module': False,
241
'is_drive': False,
242
'is_hmi': False,
243
'supports_messaging': False,
244
'ethernet_capable': True, # All discovered devices are Ethernet I/P
245
'vendor_category': 'Unknown'
246
}
247
248
# Device type analysis
249
device_type_lower = device.DeviceType.lower()
250
251
if 'programmable logic controller' in device_type_lower or 'plc' in device_type_lower:
252
capabilities['is_plc'] = True
253
capabilities['supports_messaging'] = True
254
elif 'discrete i/o' in device_type_lower or 'analog i/o' in device_type_lower:
255
capabilities['is_io_module'] = True
256
elif 'drive' in device_type_lower or 'motor' in device_type_lower:
257
capabilities['is_drive'] = True
258
elif 'human-machine interface' in device_type_lower or 'hmi' in device_type_lower:
259
capabilities['is_hmi'] = True
260
capabilities['supports_messaging'] = True
261
262
# Vendor analysis
263
vendor_lower = device.Vendor.lower()
264
if 'rockwell' in vendor_lower or 'allen-bradley' in vendor_lower:
265
capabilities['vendor_category'] = 'Rockwell Automation'
266
elif 'schneider' in vendor_lower:
267
capabilities['vendor_category'] = 'Schneider Electric'
268
elif 'siemens' in vendor_lower:
269
capabilities['vendor_category'] = 'Siemens'
270
271
return capabilities
272
273
def detailed_device_report(plc_ip):
274
"""Generate detailed device report."""
275
276
with PLC() as comm:
277
comm.IPAddress = plc_ip
278
279
# Get device properties
280
response = comm.GetDeviceProperties()
281
if response.Status != 'Success':
282
print(f"Cannot connect to device at {plc_ip}: {response.Status}")
283
return None
284
285
device = response.Value
286
capabilities = analyze_device_capabilities(device)
287
288
print(f"=== Device Report for {plc_ip} ===")
289
print(f"Product Name: {device.ProductName}")
290
print(f"Vendor: {device.Vendor} ({capabilities['vendor_category']})")
291
print(f"Device Type: {device.DeviceType}")
292
print(f"Product Code: {device.ProductCode}")
293
print(f"Firmware Revision: {device.Revision}")
294
print(f"Serial Number: {device.SerialNumber}")
295
print(f"Device Status: 0x{device.Status:04x}")
296
print(f"Device State: {device.State}")
297
print(f"Encapsulation Version: {device.EncapsulationVersion}")
298
299
print(f"\nCapabilities:")
300
print(f" PLC: {'Yes' if capabilities['is_plc'] else 'No'}")
301
print(f" I/O Module: {'Yes' if capabilities['is_io_module'] else 'No'}")
302
print(f" Drive: {'Yes' if capabilities['is_drive'] else 'No'}")
303
print(f" HMI: {'Yes' if capabilities['is_hmi'] else 'No'}")
304
print(f" Messaging Support: {'Yes' if capabilities['supports_messaging'] else 'No'}")
305
306
# If it's a PLC, get additional information
307
if capabilities['is_plc']:
308
print(f"\nPLC-Specific Information:")
309
310
# Try to get tag count
311
try:
312
tag_response = comm.GetTagList(allTags=False) # Controller tags only
313
if tag_response.Status == 'Success':
314
controller_tags = len(tag_response.Value)
315
print(f" Controller Tags: {controller_tags}")
316
317
# Try to get programs
318
program_response = comm.GetProgramsList()
319
if program_response.Status == 'Success':
320
programs = program_response.Value
321
print(f" Programs: {len(programs)}")
322
if programs:
323
for program in programs[:5]: # Show first 5
324
print(f" - {program}")
325
if len(programs) > 5:
326
print(f" ... and {len(programs) - 5} more")
327
328
except Exception as e:
329
print(f" Could not retrieve PLC details: {e}")
330
331
# Check for modules
332
print(f"\n Module Scan:")
333
modules_found = 0
334
for slot in range(8):
335
module_response = comm.GetModuleProperties(slot)
336
if module_response.Status == 'Success':
337
module = module_response.Value
338
if module.ProductName:
339
modules_found += 1
340
print(f" Slot {slot}: {module.ProductName} (Rev {module.Revision})")
341
342
if modules_found == 0:
343
print(f" No modules found or standalone PLC")
344
345
return {
346
'device': device,
347
'capabilities': capabilities,
348
'ip_address': plc_ip
349
}
350
351
# Usage
352
device_report = detailed_device_report('192.168.1.100')
353
```
354
355
### Error Handling for Discovery Operations
356
357
Discovery operations may fail due to network issues, device compatibility, or access restrictions.
358
359
```python
360
def robust_device_discovery(target_ip=None, timeout=10):
361
"""Robust device discovery with comprehensive error handling."""
362
363
results = {
364
'network_devices': [],
365
'target_device': None,
366
'errors': [],
367
'warnings': []
368
}
369
370
with PLC() as comm:
371
comm.SocketTimeout = timeout
372
373
# Network discovery
374
try:
375
print("Performing network discovery...")
376
discovery_response = comm.Discover()
377
378
if discovery_response.Status == 'Success':
379
devices = discovery_response.Value
380
results['network_devices'] = devices
381
print(f"Network discovery successful: {len(devices)} devices found")
382
else:
383
error_msg = f"Network discovery failed: {discovery_response.Status}"
384
results['errors'].append(error_msg)
385
print(error_msg)
386
387
# Check for common issues
388
if 'micropython' in discovery_response.Status.lower():
389
results['warnings'].append("Network discovery not available on MicroPython")
390
elif 'socket' in discovery_response.Status.lower():
391
results['warnings'].append("Network discovery requires socket permissions")
392
393
except Exception as e:
394
error_msg = f"Network discovery exception: {e}"
395
results['errors'].append(error_msg)
396
print(error_msg)
397
398
# Target device query
399
if target_ip:
400
try:
401
print(f"Querying target device {target_ip}...")
402
comm.IPAddress = target_ip
403
404
device_response = comm.GetDeviceProperties()
405
if device_response.Status == 'Success':
406
results['target_device'] = device_response.Value
407
print(f"Target device query successful")
408
else:
409
error_msg = f"Target device query failed: {device_response.Status}"
410
results['errors'].append(error_msg)
411
print(error_msg)
412
413
except Exception as e:
414
error_msg = f"Target device query exception: {e}"
415
results['errors'].append(error_msg)
416
print(error_msg)
417
418
# Summary
419
print(f"\nDiscovery Summary:")
420
print(f" Network devices found: {len(results['network_devices'])}")
421
print(f" Target device: {'Found' if results['target_device'] else 'Not found'}")
422
print(f" Errors: {len(results['errors'])}")
423
print(f" Warnings: {len(results['warnings'])}")
424
425
if results['errors']:
426
print("Errors encountered:")
427
for error in results['errors']:
428
print(f" - {error}")
429
430
if results['warnings']:
431
print("Warnings:")
432
for warning in results['warnings']:
433
print(f" - {warning}")
434
435
return results
436
437
# Usage
438
discovery_results = robust_device_discovery(target_ip='192.168.1.100')
439
```
440
441
### Device Status Interpretation
442
443
Understand device status codes and states for diagnostics.
444
445
```python
446
def interpret_device_status(device):
447
"""Interpret device status codes and provide diagnostic information."""
448
449
status_info = {
450
'status_code': device.Status,
451
'state_code': device.State,
452
'interpretation': {},
453
'recommendations': []
454
}
455
456
# Common status bit interpretations (device-dependent)
457
status = device.Status
458
459
if status == 0x0000:
460
status_info['interpretation']['status'] = "Normal operation"
461
elif status & 0x0001:
462
status_info['interpretation']['status'] = "Minor fault present"
463
status_info['recommendations'].append("Check device diagnostics")
464
elif status & 0x0002:
465
status_info['interpretation']['status'] = "Major fault present"
466
status_info['recommendations'].append("Device requires attention")
467
elif status & 0x0004:
468
status_info['interpretation']['status'] = "Configuration error"
469
status_info['recommendations'].append("Check device configuration")
470
471
# Device state interpretation
472
state = device.State
473
state_meanings = {
474
0: "Non-existent",
475
1: "Device operational",
476
2: "Standby",
477
3: "Major fault",
478
4: "Configuration/setup mode",
479
5: "Not configured"
480
}
481
482
status_info['interpretation']['state'] = state_meanings.get(state, f"Unknown state ({state})")
483
484
return status_info
485
486
# Usage in device reporting
487
def enhanced_device_report(plc_ip):
488
"""Enhanced device report with status interpretation."""
489
490
with PLC() as comm:
491
comm.IPAddress = plc_ip
492
response = comm.GetDeviceProperties()
493
494
if response.Status == 'Success':
495
device = response.Value
496
status_info = interpret_device_status(device)
497
498
print(f"Device Status Analysis for {plc_ip}:")
499
print(f" Status Code: 0x{device.Status:04x}")
500
print(f" Status Meaning: {status_info['interpretation'].get('status', 'Unknown')}")
501
print(f" Device State: {device.State}")
502
print(f" State Meaning: {status_info['interpretation'].get('state', 'Unknown')}")
503
504
if status_info['recommendations']:
505
print(f" Recommendations:")
506
for rec in status_info['recommendations']:
507
print(f" - {rec}")
508
else:
509
print(f"Cannot get device status for {plc_ip}: {response.Status}")
510
511
# Usage
512
enhanced_device_report('192.168.1.100')
513
```