or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

browse-operations.mdconnection-management.mdexception-handling.mdindex.mdread-operations.mdsubscription-system.mdvalue-system.mdwrite-operations.md

browse-operations.mddocs/

0

# Browse Operations

1

2

PLC namespace exploration and tag discovery capabilities for Apache PLC4X Java API.

3

4

## Capabilities

5

6

### PlcBrowseRequest

7

8

Interface for building and executing browse requests to explore PLC namespaces and discover available tags.

9

10

```java { .api }

11

/**

12

* Browse request interface for exploring PLC namespaces and discovering tags

13

*/

14

public interface PlcBrowseRequest extends PlcRequest {

15

/**

16

* Execute the browse request asynchronously

17

* @return CompletableFuture containing the browse response

18

*/

19

CompletableFuture<? extends PlcBrowseResponse> execute();

20

21

/**

22

* Execute the browse request with an interceptor for processing results

23

* @param interceptor PlcBrowseRequestInterceptor for custom result processing

24

* @return CompletableFuture containing the browse response

25

*/

26

CompletableFuture<? extends PlcBrowseResponse> executeWithInterceptor(PlcBrowseRequestInterceptor interceptor);

27

28

/**

29

* Get all query names in this browse request

30

* @return LinkedHashSet of query names

31

*/

32

LinkedHashSet<String> getQueryNames();

33

34

/**

35

* Get a specific query by name

36

* @param name Query name

37

* @return PlcQuery object

38

*/

39

PlcQuery getQuery(String name);

40

41

/**

42

* Builder interface for constructing browse requests

43

*/

44

interface Builder extends PlcRequestBuilder {

45

/**

46

* Add a browse query

47

* @param name Logical name for the query

48

* @param query Query string (protocol-specific format)

49

* @return Builder instance for method chaining

50

*/

51

Builder addQuery(String name, String query);

52

53

/**

54

* Build the browse request

55

* @return PlcBrowseRequest instance ready for execution

56

*/

57

PlcBrowseRequest build();

58

}

59

}

60

```

61

62

### PlcBrowseResponse

63

64

Interface for accessing browse response data and discovered items.

65

66

```java { .api }

67

/**

68

* Browse response interface providing access to discovered PLC items

69

*/

70

public interface PlcBrowseResponse extends PlcResponse {

71

/**

72

* Get the originating browse request

73

* @return PlcBrowseRequest that generated this response

74

*/

75

PlcBrowseRequest getRequest();

76

77

/**

78

* Get query names from the response

79

* @return Collection of query names

80

*/

81

Collection<String> getQueryNames();

82

83

/**

84

* Get response code for a specific query

85

* @param name Query name

86

* @return PlcResponseCode indicating success or failure

87

*/

88

PlcResponseCode getResponseCode(String name);

89

90

/**

91

* Get browse items for a specific query

92

* @param name Query name

93

* @return Collection of PlcBrowseItem discovered by the query

94

*/

95

Collection<PlcBrowseItem> getValues(String name);

96

}

97

```

98

99

### PlcBrowseItem

100

101

Interface representing a discovered PLC item with its properties and metadata.

102

103

```java { .api }

104

/**

105

* Interface representing a discovered PLC item

106

*/

107

public interface PlcBrowseItem {

108

/**

109

* Get the tag address for this item

110

* @return String representation of the tag address

111

*/

112

String getTag();

113

114

/**

115

* Get the display name for this item

116

* @return Human-readable name

117

*/

118

String getName();

119

120

/**

121

* Get the data type of this item

122

* @return PlcValueType indicating the data type

123

*/

124

PlcValueType getDataType();

125

126

/**

127

* Check if this item is readable

128

* @return true if item can be read

129

*/

130

boolean isReadable();

131

132

/**

133

* Check if this item is writable

134

* @return true if item can be written

135

*/

136

boolean isWritable();

137

138

/**

139

* Check if this item is subscribable

140

* @return true if item supports subscriptions

141

*/

142

boolean isSubscribable();

143

144

/**

145

* Get children items (for hierarchical structures)

146

* @return Map of child name to PlcBrowseItem

147

*/

148

Map<String, PlcBrowseItem> getChildren();

149

150

/**

151

* Get additional options/properties for this item

152

* @return Map of option names to values

153

*/

154

Map<String, PlcValue> getOptions();

155

156

/**

157

* Get array information if this item is an array

158

* @return List of ArrayInfo describing array dimensions

159

*/

160

List<ArrayInfo> getArrayInfo();

161

}

162

```

163

164

### PlcBrowseItemArrayInfo

165

166

Interface providing array dimension information for browse items.

167

168

```java { .api }

169

/**

170

* Array information for browse items

171

*/

172

public interface PlcBrowseItemArrayInfo {

173

/**

174

* Get the size of this array dimension

175

* @return Array size

176

*/

177

int getSize();

178

179

/**

180

* Get the lower bound index

181

* @return Lower bound (typically 0 or 1)

182

*/

183

int getLowerBound();

184

185

/**

186

* Get the upper bound index

187

* @return Upper bound

188

*/

189

int getUpperBound();

190

}

191

```

192

193

### PlcBrowseRequestInterceptor

194

195

Interface for intercepting and processing browse results.

196

197

```java { .api }

198

/**

199

* Interceptor interface for processing browse results during execution

200

*/

201

public interface PlcBrowseRequestInterceptor {

202

/**

203

* Intercept and process a browse item

204

* @param browseItem The discovered browse item

205

* @return Modified or filtered browse item, or null to exclude

206

*/

207

PlcBrowseItem intercept(PlcBrowseItem browseItem);

208

}

209

```

210

211

**Usage Examples:**

212

213

```java

214

import org.apache.plc4x.java.DefaultPlcDriverManager;

215

import org.apache.plc4x.java.api.PlcConnection;

216

import org.apache.plc4x.java.api.messages.*;

217

import org.apache.plc4x.java.api.model.PlcQuery;

218

import org.apache.plc4x.java.api.types.PlcResponseCode;

219

import org.apache.plc4x.java.api.types.PlcValueType;

220

221

// Basic browse operation

222

PlcDriverManager driverManager = new DefaultPlcDriverManager();

223

try (PlcConnection connection = driverManager.getConnection("s7://192.168.1.200/0/1")) {

224

connection.connect();

225

226

// Check if browsing is supported

227

if (connection.getMetadata().isBrowseSupported()) {

228

// Build browse request

229

PlcBrowseRequest browseRequest = connection.browseRequestBuilder()

230

.addQuery("root", "*") // Browse all items at root level

231

.build();

232

233

PlcBrowseResponse response = browseRequest.execute().get();

234

235

if (response.getResponseCode("root") == PlcResponseCode.OK) {

236

Collection<PlcBrowseItem> items = response.getValues("root");

237

238

System.out.println("Discovered " + items.size() + " items:");

239

for (PlcBrowseItem item : items) {

240

System.out.println("- " + item.getName() +

241

" (" + item.getTag() + ")" +

242

" Type: " + item.getDataType() +

243

" R:" + item.isReadable() +

244

" W:" + item.isWritable() +

245

" S:" + item.isSubscribable());

246

}

247

}

248

} else {

249

System.out.println("Browsing not supported by this connection");

250

}

251

}

252

253

// Hierarchical browsing

254

try (PlcConnection connection = driverManager.getConnection("s7://192.168.1.200/0/1")) {

255

connection.connect();

256

257

PlcBrowseRequest browseRequest = connection.browseRequestBuilder()

258

.addQuery("data_blocks", "DB*") // Browse all data blocks

259

.addQuery("memory_areas", "M*") // Browse memory areas

260

.addQuery("inputs", "I*") // Browse inputs

261

.addQuery("outputs", "Q*") // Browse outputs

262

.build();

263

264

PlcBrowseResponse response = browseRequest.execute().get();

265

266

// Process each query result

267

for (String queryName : response.getQueryNames()) {

268

System.out.println("\n=== " + queryName.toUpperCase() + " ===");

269

270

if (response.getResponseCode(queryName) == PlcResponseCode.OK) {

271

Collection<PlcBrowseItem> items = response.getValues(queryName);

272

273

for (PlcBrowseItem item : items) {

274

printBrowseItemDetails(item, 0);

275

276

// Explore children if available

277

if (!item.getChildren().isEmpty()) {

278

item.getChildren().forEach((childName, childItem) -> {

279

printBrowseItemDetails(childItem, 1);

280

});

281

}

282

}

283

} else {

284

System.out.println("Query failed: " + response.getResponseCode(queryName));

285

}

286

}

287

}

288

289

// Filtered browsing with interceptor

290

try (PlcConnection connection = driverManager.getConnection("modbus-tcp://192.168.1.100:502")) {

291

connection.connect();

292

293

// Create interceptor to filter only writable items

294

PlcBrowseRequestInterceptor writableFilter = browseItem -> {

295

if (browseItem.isWritable()) {

296

return browseItem; // Keep writable items

297

}

298

return null; // Filter out read-only items

299

};

300

301

PlcBrowseRequest browseRequest = connection.browseRequestBuilder()

302

.addQuery("writable_registers", "holding-register:*")

303

.build();

304

305

PlcBrowseResponse response = browseRequest.executeWithInterceptor(writableFilter).get();

306

307

if (response.getResponseCode("writable_registers") == PlcResponseCode.OK) {

308

Collection<PlcBrowseItem> writableItems = response.getValues("writable_registers");

309

310

System.out.println("Found " + writableItems.size() + " writable registers:");

311

for (PlcBrowseItem item : writableItems) {

312

System.out.println("- " + item.getTag() + " (" + item.getDataType() + ")");

313

}

314

}

315

}

316

317

// Array item discovery

318

try (PlcConnection connection = driverManager.getConnection("s7://192.168.1.200/0/1")) {

319

connection.connect();

320

321

PlcBrowseRequest browseRequest = connection.browseRequestBuilder()

322

.addQuery("arrays", "DB1.*[*]") // Browse array items in DB1

323

.build();

324

325

PlcBrowseResponse response = browseRequest.execute().get();

326

327

if (response.getResponseCode("arrays") == PlcResponseCode.OK) {

328

Collection<PlcBrowseItem> arrayItems = response.getValues("arrays");

329

330

for (PlcBrowseItem item : arrayItems) {

331

System.out.println("Array: " + item.getName());

332

System.out.println(" Tag: " + item.getTag());

333

System.out.println(" Type: " + item.getDataType());

334

335

// Display array dimension information

336

List<ArrayInfo> arrayInfo = item.getArrayInfo();

337

if (!arrayInfo.isEmpty()) {

338

System.out.println(" Dimensions:");

339

for (int i = 0; i < arrayInfo.size(); i++) {

340

ArrayInfo dimension = arrayInfo.get(i);

341

System.out.println(" [" + i + "]: " + dimension.getLowerBound() +

342

".." + dimension.getUpperBound() +

343

" (size: " + dimension.getSize() + ")");

344

}

345

}

346

}

347

}

348

}

349

350

// Browse with specific data type filtering

351

try (PlcConnection connection = driverManager.getConnection("s7://192.168.1.200/0/1")) {

352

connection.connect();

353

354

PlcBrowseRequest browseRequest = connection.browseRequestBuilder()

355

.addQuery("all_items", "*")

356

.build();

357

358

PlcBrowseResponse response = browseRequest.execute().get();

359

360

if (response.getResponseCode("all_items") == PlcResponseCode.OK) {

361

Collection<PlcBrowseItem> allItems = response.getValues("all_items");

362

363

// Group items by data type

364

Map<PlcValueType, List<PlcBrowseItem>> itemsByType = allItems.stream()

365

.collect(Collectors.groupingBy(PlcBrowseItem::getDataType));

366

367

itemsByType.forEach((dataType, items) -> {

368

System.out.println("\n" + dataType + " items (" + items.size() + "):");

369

items.forEach(item -> {

370

System.out.println(" - " + item.getName() + " (" + item.getTag() + ")");

371

});

372

});

373

}

374

}

375

376

// Metadata and options exploration

377

try (PlcConnection connection = driverManager.getConnection("s7://192.168.1.200/0/1")) {

378

connection.connect();

379

380

PlcBrowseRequest browseRequest = connection.browseRequestBuilder()

381

.addQuery("detailed", "DB10.*")

382

.build();

383

384

PlcBrowseResponse response = browseRequest.execute().get();

385

386

if (response.getResponseCode("detailed") == PlcResponseCode.OK) {

387

Collection<PlcBrowseItem> items = response.getValues("detailed");

388

389

for (PlcBrowseItem item : items) {

390

System.out.println("\nItem: " + item.getName());

391

System.out.println(" Tag: " + item.getTag());

392

System.out.println(" Type: " + item.getDataType());

393

System.out.println(" Readable: " + item.isReadable());

394

System.out.println(" Writable: " + item.isWritable());

395

System.out.println(" Subscribable: " + item.isSubscribable());

396

397

// Display additional options/metadata

398

Map<String, PlcValue> options = item.getOptions();

399

if (!options.isEmpty()) {

400

System.out.println(" Options:");

401

options.forEach((optionName, optionValue) -> {

402

System.out.println(" " + optionName + ": " + optionValue.getObject());

403

});

404

}

405

}

406

}

407

}

408

409

// Helper method for displaying browse item details

410

private static void printBrowseItemDetails(PlcBrowseItem item, int indentLevel) {

411

String indent = " ".repeat(indentLevel);

412

System.out.printf("%s- %s (%s) [%s] R:%s W:%s S:%s%n",

413

indent,

414

item.getName(),

415

item.getTag(),

416

item.getDataType(),

417

item.isReadable() ? "Y" : "N",

418

item.isWritable() ? "Y" : "N",

419

item.isSubscribable() ? "Y" : "N"

420

);

421

422

// Show array information if present

423

if (!item.getArrayInfo().isEmpty()) {

424

System.out.print(indent + " Array: ");

425

for (ArrayInfo arrayInfo : item.getArrayInfo()) {

426

System.out.printf("[%d..%d] ", arrayInfo.getLowerBound(), arrayInfo.getUpperBound());

427

}

428

System.out.println();

429

}

430

}

431

```

432

433

## Types

434

435

### Query and Discovery Types

436

437

```java { .api }

438

public interface PlcQuery {

439

/**

440

* Get the query string

441

* @return Query string in protocol-specific format

442

*/

443

String getQueryString();

444

}

445

446

public interface PlcDiscoveryRequest extends PlcRequest {

447

CompletableFuture<? extends PlcDiscoveryResponse> execute();

448

}

449

450

public interface PlcDiscoveryResponse extends PlcResponse {

451

PlcDiscoveryRequest getRequest();

452

Collection<PlcDiscoveryItem> getValues();

453

}

454

455

public interface PlcDiscoveryItem {

456

String getProtocolCode();

457

String getTransportCode();

458

String getTransportUrl();

459

String getOptions();

460

String getName();

461

}

462

463

public interface PlcDiscoveryItemHandler {

464

void handle(PlcDiscoveryItem discoveryItem);

465

}

466

```

467

468

### Model Types

469

470

```java { .api }

471

public interface ArrayInfo {

472

int getSize();

473

int getLowerBound();

474

int getUpperBound();

475

}

476

```

477

478

## Browse Query Patterns

479

480

Different PLC protocols support different browse query patterns:

481

482

### Siemens S7

483

- `*` - Browse all items at current level

484

- `DB*` - Browse all data blocks

485

- `DB1.*` - Browse all items in data block 1

486

- `DB1.DBD*` - Browse all double words in data block 1

487

- `M*` - Browse all memory areas

488

- `I*` - Browse all inputs

489

- `Q*` - Browse all outputs

490

491

### Modbus

492

- `*` - Browse all available registers

493

- `holding-register:*` - Browse all holding registers

494

- `input-register:*` - Browse all input registers

495

- `coil:*` - Browse all coils

496

- `discrete-input:*` - Browse all discrete inputs

497

498

### OPC UA

499

- `*` - Browse all nodes at current level

500

- `Objects.*` - Browse all objects

501

- `Types.*` - Browse all type definitions

502

- `Views.*` - Browse all views

503

504

Browse operations provide a powerful way to discover and explore PLC namespaces without prior knowledge of the tag structure, making it ideal for debugging, development, and dynamic tag discovery scenarios.