0
# Tag Discovery and Introspection
1
2
Comprehensive capabilities for discovering available tags, programs, and retrieving detailed tag metadata including data types, structure information, and User Defined Types (UDTs). These functions enable dynamic PLC interaction and automated tag management.
3
4
## Capabilities
5
6
### Complete Tag List Discovery
7
8
Retrieve the complete list of tags available in the PLC, including both controller-scoped and program-scoped tags.
9
10
```python { .api }
11
def GetTagList(allTags=True):
12
"""
13
Retrieve the complete tag list from the PLC.
14
15
Args:
16
allTags (bool): If True, include both controller and program tags.
17
If False, return only controller-scoped tags.
18
19
Returns:
20
Response: Object containing list of Tag objects with metadata
21
- Value: List of Tag objects
22
- Status: "Success" or error description
23
"""
24
```
25
26
**Usage Examples:**
27
28
```python
29
from pylogix import PLC
30
31
with PLC() as comm:
32
comm.IPAddress = '192.168.1.100'
33
34
# Get all tags (controller and program tags)
35
response = comm.GetTagList(allTags=True)
36
if response.Status == 'Success':
37
tags = response.Value
38
print(f"Found {len(tags)} total tags")
39
40
# Display tag information
41
for tag in tags[:10]: # Show first 10 tags
42
print(f"Tag: {tag.TagName}")
43
print(f" Type: {tag.DataType}")
44
print(f" Array: {'Yes' if tag.Array else 'No'}")
45
print(f" Struct: {'Yes' if tag.Struct else 'No'}")
46
if tag.Array:
47
print(f" Size: {tag.Size}")
48
print()
49
50
# Get only controller-scoped tags
51
response = comm.GetTagList(allTags=False)
52
if response.Status == 'Success':
53
controller_tags = response.Value
54
print(f"Controller tags only: {len(controller_tags)}")
55
```
56
57
### Program-Specific Tag Discovery
58
59
Retrieve tags that belong to a specific program within the PLC.
60
61
```python { .api }
62
def GetProgramTagList(programName):
63
"""
64
Get tags for a specific program.
65
66
Args:
67
programName (str): Program name in format "Program:ProgramName"
68
69
Returns:
70
Response: Object containing list of Tag objects for the program
71
- Value: List of program-specific Tag objects
72
- Status: "Success" or error description
73
"""
74
```
75
76
**Usage Examples:**
77
78
```python
79
with PLC() as comm:
80
comm.IPAddress = '192.168.1.100'
81
82
# Get tags for a specific program
83
response = comm.GetProgramTagList("Program:MainProgram")
84
if response.Status == 'Success':
85
program_tags = response.Value
86
print(f"Tags in MainProgram: {len(program_tags)}")
87
88
for tag in program_tags:
89
print(f" {tag.TagName} ({tag.DataType})")
90
else:
91
print(f"Failed to get program tags: {response.Status}")
92
93
# Try different program
94
response = comm.GetProgramTagList("Program:SafetyProgram")
95
if response.Status == 'Success':
96
safety_tags = response.Value
97
print(f"Safety program has {len(safety_tags)} tags")
98
```
99
100
### Program List Discovery
101
102
Discover all available programs in the PLC before querying their specific tags.
103
104
```python { .api }
105
def GetProgramsList():
106
"""
107
Get list of available programs in the PLC.
108
109
Returns:
110
Response: Object containing list of program names
111
- Value: List of program name strings
112
- Status: "Success" or error description
113
"""
114
```
115
116
**Usage Examples:**
117
118
```python
119
with PLC() as comm:
120
comm.IPAddress = '192.168.1.100'
121
122
# Discover all programs
123
response = comm.GetProgramsList()
124
if response.Status == 'Success':
125
programs = response.Value
126
print(f"Available programs: {len(programs)}")
127
128
for program in programs:
129
print(f" - {program}")
130
131
# Get tags for each program
132
for program in programs:
133
prog_response = comm.GetProgramTagList(program)
134
if prog_response.Status == 'Success':
135
tag_count = len(prog_response.Value)
136
print(f" {program}: {tag_count} tags")
137
else:
138
print(f"Failed to get programs list: {response.Status}")
139
```
140
141
### Tag Metadata Analysis
142
143
Work with detailed tag metadata to understand PLC structure and data organization.
144
145
**Tag Object Properties:**
146
147
```python
148
# After getting tag list, analyze tag properties
149
response = comm.GetTagList()
150
if response.Status == 'Success':
151
tags = response.Value
152
153
for tag in tags:
154
print(f"Tag: {tag.TagName}")
155
print(f" Instance ID: {tag.InstanceID}")
156
print(f" Symbol Type: 0x{tag.SymbolType:02x}")
157
print(f" Data Type Value: 0x{tag.DataTypeValue:03x}")
158
print(f" Data Type: {tag.DataType}")
159
print(f" Is Array: {bool(tag.Array)}")
160
print(f" Is Struct: {bool(tag.Struct)}")
161
print(f" Size: {tag.Size}")
162
if hasattr(tag, 'AccessRight') and tag.AccessRight is not None:
163
print(f" Access Right: {tag.AccessRight}")
164
print()
165
```
166
167
### Data Type Classification
168
169
Organize tags by their data types for systematic processing.
170
171
```python
172
def classify_tags_by_type(tags):
173
"""Classify tags by their data types."""
174
classification = {
175
'Integers': [],
176
'Floats': [],
177
'Booleans': [],
178
'Strings': [],
179
'Arrays': [],
180
'Structures': [],
181
'Unknown': []
182
}
183
184
for tag in tags:
185
if tag.DataType in ['DINT', 'INT', 'SINT', 'UDINT', 'UINT', 'USINT', 'LINT']:
186
classification['Integers'].append(tag)
187
elif tag.DataType in ['REAL', 'LREAL']:
188
classification['Floats'].append(tag)
189
elif tag.DataType == 'BOOL':
190
classification['Booleans'].append(tag)
191
elif tag.DataType == 'STRING':
192
classification['Strings'].append(tag)
193
elif tag.Array:
194
classification['Arrays'].append(tag)
195
elif tag.Struct:
196
classification['Structures'].append(tag)
197
else:
198
classification['Unknown'].append(tag)
199
200
return classification
201
202
# Usage
203
with PLC() as comm:
204
comm.IPAddress = '192.168.1.100'
205
response = comm.GetTagList()
206
207
if response.Status == 'Success':
208
classified = classify_tags_by_type(response.Value)
209
210
for category, tag_list in classified.items():
211
if tag_list:
212
print(f"{category}: {len(tag_list)} tags")
213
for tag in tag_list[:3]: # Show first 3 in each category
214
print(f" - {tag.TagName}")
215
if len(tag_list) > 3:
216
print(f" ... and {len(tag_list) - 3} more")
217
print()
218
```
219
220
### User Defined Type (UDT) Discovery
221
222
Discover and analyze User Defined Types (UDTs) and their field structures.
223
224
```python
225
def discover_udts(plc_comm):
226
"""Discover all UDTs and their structures."""
227
response = plc_comm.GetTagList()
228
if response.Status != 'Success':
229
return None
230
231
tags = response.Value
232
udts = {}
233
234
# Find all UDT instances
235
for tag in tags:
236
if tag.Struct and tag.DataType:
237
if tag.DataType not in udts:
238
udts[tag.DataType] = {
239
'instances': [],
240
'fields': set()
241
}
242
udts[tag.DataType]['instances'].append(tag.TagName)
243
244
# Access UDT definitions from PLC object
245
if hasattr(plc_comm, 'UDTByName'):
246
for udt_name, udt_info in udts.items():
247
if udt_name in plc_comm.UDTByName:
248
udt_def = plc_comm.UDTByName[udt_name]
249
udt_info['definition'] = udt_def
250
udt_info['fields'] = [field.TagName for field in udt_def.Fields]
251
252
return udts
253
254
# Usage
255
with PLC() as comm:
256
comm.IPAddress = '192.168.1.100'
257
258
udts = discover_udts(comm)
259
if udts:
260
print("Discovered UDTs:")
261
for udt_name, info in udts.items():
262
print(f"\nUDT: {udt_name}")
263
print(f" Instances: {len(info['instances'])}")
264
for instance in info['instances'][:3]:
265
print(f" - {instance}")
266
if len(info['instances']) > 3:
267
print(f" ... and {len(info['instances']) - 3} more")
268
269
if 'fields' in info and info['fields']:
270
print(f" Fields: {len(info['fields'])}")
271
for field in info['fields'][:5]: # Show first 5 fields
272
print(f" - {field}")
273
if len(info['fields']) > 5:
274
print(f" ... and {len(info['fields']) - 5} more")
275
```
276
277
### Tag Filtering and Search
278
279
Implement search and filtering capabilities for large tag lists.
280
281
```python
282
def search_tags(tags, search_pattern, case_sensitive=False):
283
"""Search tags by name pattern."""
284
import re
285
286
if not case_sensitive:
287
pattern = re.compile(search_pattern, re.IGNORECASE)
288
else:
289
pattern = re.compile(search_pattern)
290
291
matching_tags = []
292
for tag in tags:
293
if pattern.search(tag.TagName):
294
matching_tags.append(tag)
295
296
return matching_tags
297
298
def filter_tags_by_type(tags, data_types):
299
"""Filter tags by data type."""
300
if isinstance(data_types, str):
301
data_types = [data_types]
302
303
filtered_tags = []
304
for tag in tags:
305
if tag.DataType in data_types:
306
filtered_tags.append(tag)
307
308
return filtered_tags
309
310
# Usage examples
311
with PLC() as comm:
312
comm.IPAddress = '192.168.1.100'
313
response = comm.GetTagList()
314
315
if response.Status == 'Success':
316
all_tags = response.Value
317
318
# Search for motor-related tags
319
motor_tags = search_tags(all_tags, r'motor|drive|speed', case_sensitive=False)
320
print(f"Motor-related tags: {len(motor_tags)}")
321
322
# Find all temperature tags
323
temp_tags = search_tags(all_tags, r'temp|temperature', case_sensitive=False)
324
print(f"Temperature tags: {len(temp_tags)}")
325
326
# Get all REAL (float) tags
327
float_tags = filter_tags_by_type(all_tags, 'REAL')
328
print(f"Float tags: {len(float_tags)}")
329
330
# Get all boolean tags
331
bool_tags = filter_tags_by_type(all_tags, 'BOOL')
332
print(f"Boolean tags: {len(bool_tags)}")
333
```
334
335
### Complete Tag Inventory
336
337
Create a comprehensive inventory of all PLC tags with their properties.
338
339
```python
340
def create_tag_inventory(plc_ip, output_file=None):
341
"""Create a complete tag inventory."""
342
inventory = {
343
'plc_ip': plc_ip,
344
'discovery_time': None,
345
'controller_tags': [],
346
'program_tags': {},
347
'programs': [],
348
'udts': {},
349
'summary': {
350
'total_tags': 0,
351
'controller_tags': 0,
352
'program_tags': 0,
353
'data_types': {},
354
'arrays': 0,
355
'structures': 0
356
}
357
}
358
359
with PLC() as comm:
360
comm.IPAddress = plc_ip
361
362
# Get timestamp
363
from datetime import datetime
364
inventory['discovery_time'] = datetime.now().isoformat()
365
366
# Get all tags
367
response = comm.GetTagList(allTags=True)
368
if response.Status != 'Success':
369
print(f"Failed to get tag list: {response.Status}")
370
return None
371
372
all_tags = response.Value
373
inventory['summary']['total_tags'] = len(all_tags)
374
375
# Separate controller and program tags
376
for tag in all_tags:
377
if 'Program:' in tag.TagName:
378
program_name = tag.TagName.split('.')[0]
379
if program_name not in inventory['program_tags']:
380
inventory['program_tags'][program_name] = []
381
inventory['program_tags'][program_name].append({
382
'name': tag.TagName,
383
'type': tag.DataType,
384
'array': bool(tag.Array),
385
'struct': bool(tag.Struct),
386
'size': tag.Size
387
})
388
inventory['summary']['program_tags'] += 1
389
else:
390
inventory['controller_tags'].append({
391
'name': tag.TagName,
392
'type': tag.DataType,
393
'array': bool(tag.Array),
394
'struct': bool(tag.Struct),
395
'size': tag.Size
396
})
397
inventory['summary']['controller_tags'] += 1
398
399
# Update summary statistics
400
data_type = tag.DataType or 'Unknown'
401
inventory['summary']['data_types'][data_type] = \
402
inventory['summary']['data_types'].get(data_type, 0) + 1
403
404
if tag.Array:
405
inventory['summary']['arrays'] += 1
406
if tag.Struct:
407
inventory['summary']['structures'] += 1
408
409
# Get programs list
410
programs_response = comm.GetProgramsList()
411
if programs_response.Status == 'Success':
412
inventory['programs'] = programs_response.Value
413
414
# Export to file if requested
415
if output_file:
416
import json
417
with open(output_file, 'w') as f:
418
json.dump(inventory, f, indent=2)
419
print(f"Tag inventory saved to {output_file}")
420
421
return inventory
422
423
# Usage
424
inventory = create_tag_inventory('192.168.1.100', 'plc_inventory.json')
425
if inventory:
426
print(f"PLC Inventory Summary:")
427
print(f" Total tags: {inventory['summary']['total_tags']}")
428
print(f" Controller tags: {inventory['summary']['controller_tags']}")
429
print(f" Program tags: {inventory['summary']['program_tags']}")
430
print(f" Programs: {len(inventory['programs'])}")
431
print(f" Arrays: {inventory['summary']['arrays']}")
432
print(f" Structures: {inventory['summary']['structures']}")
433
print(f" Data types:")
434
for dt, count in inventory['summary']['data_types'].items():
435
print(f" {dt}: {count}")
436
```
437
438
### Error Handling for Discovery Operations
439
440
Discovery operations can fail or return partial results. Implement proper error handling:
441
442
```python
443
def robust_tag_discovery(plc_ip, max_retries=3):
444
"""Robust tag discovery with error handling."""
445
446
for attempt in range(max_retries):
447
try:
448
with PLC() as comm:
449
comm.IPAddress = plc_ip
450
comm.SocketTimeout = 30.0 # Longer timeout for large tag lists
451
452
# Try to get tag list
453
response = comm.GetTagList()
454
455
if response.Status == 'Success':
456
tags = response.Value
457
if tags: # Make sure we got some tags
458
print(f"Successfully discovered {len(tags)} tags")
459
return tags
460
else:
461
print("Got empty tag list")
462
else:
463
print(f"Tag discovery attempt {attempt + 1} failed: {response.Status}")
464
465
except Exception as e:
466
print(f"Exception during discovery attempt {attempt + 1}: {e}")
467
468
if attempt < max_retries - 1:
469
print(f"Retrying tag discovery...")
470
import time
471
time.sleep(2)
472
473
print(f"Failed to discover tags after {max_retries} attempts")
474
return None
475
476
# Usage
477
tags = robust_tag_discovery('192.168.1.100')
478
if tags:
479
print("Tag discovery successful")
480
# Process tags...
481
else:
482
print("Tag discovery failed")
483
```