or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-messaging.mdcore-operations.mddevice-discovery.mdindex.mdtag-discovery.mdtime-operations.md

tag-discovery.mddocs/

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

```