or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ble-discovery.mdclusters.mdcrypto-credentials.mddevice-controller.mdindex.mdstack-management.mdstorage.mdtlv-data.md

tlv-data.mddocs/

0

# TLV Data Handling

1

2

TLV (Tag-Length-Value) encoding and decoding for Matter protocol data structures, enabling low-level protocol operations and custom data handling.

3

4

## Capabilities

5

6

### TLV Writer

7

8

Encode data into TLV format for Matter protocol transmission.

9

10

```python { .api }

11

class TLVWriter:

12

"""TLV encoder for Matter protocol data structures."""

13

14

def __init__(self):

15

"""Initialize TLV writer."""

16

...

17

18

def put(self, tag: int, value) -> bool:

19

"""

20

Write a tagged value to the TLV stream.

21

22

Parameters:

23

- tag: TLV tag identifier

24

- value: Value to encode (int, float, str, bytes, bool, list, dict)

25

26

Returns:

27

True if write successful

28

"""

29

...

30

31

def put_null(self, tag: int) -> bool:

32

"""

33

Write a null value.

34

35

Parameters:

36

- tag: TLV tag identifier

37

38

Returns:

39

True if write successful

40

"""

41

...

42

43

def put_bool(self, tag: int, value: bool) -> bool:

44

"""

45

Write a boolean value.

46

47

Parameters:

48

- tag: TLV tag identifier

49

- value: Boolean value

50

51

Returns:

52

True if write successful

53

"""

54

...

55

56

def put_int(self, tag: int, value: int) -> bool:

57

"""

58

Write a signed integer value.

59

60

Parameters:

61

- tag: TLV tag identifier

62

- value: Integer value

63

64

Returns:

65

True if write successful

66

"""

67

...

68

69

def put_uint(self, tag: int, value: int) -> bool:

70

"""

71

Write an unsigned integer value.

72

73

Parameters:

74

- tag: TLV tag identifier

75

- value: Unsigned integer value

76

77

Returns:

78

True if write successful

79

"""

80

...

81

82

def put_float(self, tag: int, value: float) -> bool:

83

"""

84

Write a floating-point value.

85

86

Parameters:

87

- tag: TLV tag identifier

88

- value: Float value (32-bit or 64-bit)

89

90

Returns:

91

True if write successful

92

"""

93

...

94

95

def put_string(self, tag: int, value: str) -> bool:

96

"""

97

Write a UTF-8 string value.

98

99

Parameters:

100

- tag: TLV tag identifier

101

- value: String value

102

103

Returns:

104

True if write successful

105

"""

106

...

107

108

def put_bytes(self, tag: int, value: bytes) -> bool:

109

"""

110

Write a byte string value.

111

112

Parameters:

113

- tag: TLV tag identifier

114

- value: Byte string value

115

116

Returns:

117

True if write successful

118

"""

119

...

120

121

def start_container(self, tag: int, container_type: int) -> bool:

122

"""

123

Start a TLV container (structure, array, or list).

124

125

Parameters:

126

- tag: TLV tag identifier

127

- container_type: Container type (0=Structure, 1=Array, 2=List)

128

129

Returns:

130

True if container started successfully

131

"""

132

...

133

134

def end_container(self) -> bool:

135

"""

136

End the current TLV container.

137

138

Returns:

139

True if container ended successfully

140

"""

141

...

142

143

def finalize(self) -> bytes:

144

"""

145

Finalize the TLV encoding and return the encoded data.

146

147

Returns:

148

Encoded TLV data as bytes

149

"""

150

...

151

152

def get_length(self) -> int:

153

"""

154

Get the length of encoded data so far.

155

156

Returns:

157

Number of encoded bytes

158

"""

159

...

160

161

def reset(self):

162

"""Reset the writer to start encoding new data."""

163

...

164

```

165

166

### TLV Reader

167

168

Decode TLV formatted data from Matter protocol messages.

169

170

```python { .api }

171

class TLVReader:

172

"""TLV decoder for Matter protocol data structures."""

173

174

def __init__(self, data: bytes):

175

"""

176

Initialize TLV reader with encoded data.

177

178

Parameters:

179

- data: TLV encoded data bytes

180

"""

181

...

182

183

def get(self, tag: int):

184

"""

185

Get value by tag.

186

187

Parameters:

188

- tag: TLV tag identifier to find

189

190

Returns:

191

Decoded value or None if tag not found

192

"""

193

...

194

195

def get_bool(self, tag: int) -> bool:

196

"""

197

Get boolean value by tag.

198

199

Parameters:

200

- tag: TLV tag identifier

201

202

Returns:

203

Boolean value or None if tag not found

204

205

Raises:

206

ValueError: If tag exists but is not a boolean

207

"""

208

...

209

210

def get_int(self, tag: int) -> int:

211

"""

212

Get signed integer value by tag.

213

214

Parameters:

215

- tag: TLV tag identifier

216

217

Returns:

218

Integer value or None if tag not found

219

220

Raises:

221

ValueError: If tag exists but is not an integer

222

"""

223

...

224

225

def get_uint(self, tag: int) -> int:

226

"""

227

Get unsigned integer value by tag.

228

229

Parameters:

230

- tag: TLV tag identifier

231

232

Returns:

233

Unsigned integer value or None if tag not found

234

235

Raises:

236

ValueError: If tag exists but is not an unsigned integer

237

"""

238

...

239

240

def get_float(self, tag: int) -> float:

241

"""

242

Get floating-point value by tag.

243

244

Parameters:

245

- tag: TLV tag identifier

246

247

Returns:

248

Float value or None if tag not found

249

250

Raises:

251

ValueError: If tag exists but is not a float

252

"""

253

...

254

255

def get_string(self, tag: int) -> str:

256

"""

257

Get UTF-8 string value by tag.

258

259

Parameters:

260

- tag: TLV tag identifier

261

262

Returns:

263

String value or None if tag not found

264

265

Raises:

266

ValueError: If tag exists but is not a string

267

"""

268

...

269

270

def get_bytes(self, tag: int) -> bytes:

271

"""

272

Get byte string value by tag.

273

274

Parameters:

275

- tag: TLV tag identifier

276

277

Returns:

278

Byte string value or None if tag not found

279

280

Raises:

281

ValueError: If tag exists but is not a byte string

282

"""

283

...

284

285

def get_all(self) -> dict:

286

"""

287

Get all tag-value pairs.

288

289

Returns:

290

Dictionary mapping tags to decoded values

291

"""

292

...

293

294

def get_tags(self) -> list:

295

"""

296

Get all tags in the TLV data.

297

298

Returns:

299

List of tag identifiers

300

"""

301

...

302

303

def has_tag(self, tag: int) -> bool:

304

"""

305

Check if a tag exists in the TLV data.

306

307

Parameters:

308

- tag: TLV tag identifier

309

310

Returns:

311

True if tag exists

312

"""

313

...

314

315

def get_container(self, tag: int) -> 'TLVReader':

316

"""

317

Get a container (structure, array, or list) as a new TLV reader.

318

319

Parameters:

320

- tag: TLV tag identifier for the container

321

322

Returns:

323

New TLVReader for the container contents or None if not found

324

325

Raises:

326

ValueError: If tag exists but is not a container

327

"""

328

...

329

330

def is_container(self, tag: int) -> bool:

331

"""

332

Check if a tag contains a container.

333

334

Parameters:

335

- tag: TLV tag identifier

336

337

Returns:

338

True if tag contains a container

339

"""

340

...

341

342

def get_container_type(self, tag: int) -> int:

343

"""

344

Get the type of a container.

345

346

Parameters:

347

- tag: TLV tag identifier for the container

348

349

Returns:

350

Container type (0=Structure, 1=Array, 2=List) or None if not a container

351

"""

352

...

353

```

354

355

### TLV Utility Functions

356

357

Utility functions for common TLV operations and data type handling.

358

359

```python { .api }

360

class TLVUtils:

361

"""Utility functions for TLV operations."""

362

363

@staticmethod

364

def encode_tag(profile_id: int, tag_num: int, is_context_specific: bool = False) -> int:

365

"""

366

Encode a TLV tag from profile ID and tag number.

367

368

Parameters:

369

- profile_id: Profile identifier (0 for anonymous)

370

- tag_num: Tag number within the profile

371

- is_context_specific: Whether this is a context-specific tag

372

373

Returns:

374

Encoded tag value

375

"""

376

...

377

378

@staticmethod

379

def decode_tag(tag: int) -> dict:

380

"""

381

Decode a TLV tag into its components.

382

383

Parameters:

384

- tag: Encoded tag value

385

386

Returns:

387

Dictionary with 'profile_id', 'tag_num', and 'is_context_specific'

388

"""

389

...

390

391

@staticmethod

392

def python_to_tlv(data) -> bytes:

393

"""

394

Convert Python data structure to TLV bytes.

395

396

Parameters:

397

- data: Python data (dict, list, primitive types)

398

399

Returns:

400

TLV encoded bytes

401

"""

402

...

403

404

@staticmethod

405

def tlv_to_python(data: bytes) -> dict:

406

"""

407

Convert TLV bytes to Python data structure.

408

409

Parameters:

410

- data: TLV encoded bytes

411

412

Returns:

413

Python data structure (dict with tag keys)

414

"""

415

...

416

417

@staticmethod

418

def validate_tlv(data: bytes) -> bool:

419

"""

420

Validate TLV data structure.

421

422

Parameters:

423

- data: TLV encoded bytes to validate

424

425

Returns:

426

True if TLV data is well-formed

427

"""

428

...

429

430

@staticmethod

431

def pretty_print_tlv(data: bytes) -> str:

432

"""

433

Create a human-readable representation of TLV data.

434

435

Parameters:

436

- data: TLV encoded bytes

437

438

Returns:

439

Formatted string representation

440

"""

441

...

442

443

@staticmethod

444

def get_tlv_size(data: bytes) -> int:

445

"""

446

Get the total size of TLV data.

447

448

Parameters:

449

- data: TLV encoded bytes

450

451

Returns:

452

Size in bytes

453

"""

454

...

455

```

456

457

### Matter-Specific TLV Types

458

459

TLV handling for Matter-specific data types and structures.

460

461

```python { .api }

462

class float32:

463

"""32-bit floating point TLV type."""

464

465

def __init__(self, value: float):

466

"""

467

Initialize 32-bit float.

468

469

Parameters:

470

- value: Float value

471

"""

472

...

473

474

@property

475

def value(self) -> float:

476

"""Get the float value."""

477

...

478

479

class uint:

480

"""Unsigned integer TLV type with size specification."""

481

482

def __init__(self, value: int, size: int = None):

483

"""

484

Initialize unsigned integer.

485

486

Parameters:

487

- value: Integer value

488

- size: Size in bytes (1, 2, 4, or 8), auto-detected if None

489

"""

490

...

491

492

@property

493

def value(self) -> int:

494

"""Get the integer value."""

495

...

496

497

@property

498

def size(self) -> int:

499

"""Get the size in bytes."""

500

...

501

502

class int:

503

"""Signed integer TLV type with size specification."""

504

505

def __init__(self, value: int, size: int = None):

506

"""

507

Initialize signed integer.

508

509

Parameters:

510

- value: Integer value

511

- size: Size in bytes (1, 2, 4, or 8), auto-detected if None

512

"""

513

...

514

515

@property

516

def value(self) -> int:

517

"""Get the integer value."""

518

...

519

520

@property

521

def size(self) -> int:

522

"""Get the size in bytes."""

523

...

524

```

525

526

## Usage Examples

527

528

### Basic TLV Encoding and Decoding

529

530

```python

531

from chip.tlv import TLVWriter, TLVReader

532

533

# Create a TLV writer

534

writer = TLVWriter()

535

536

# Encode various data types

537

writer.put_int(1, 42) # Tag 1: integer 42

538

writer.put_string(2, "Hello, Matter!") # Tag 2: string

539

writer.put_bool(3, True) # Tag 3: boolean true

540

writer.put_float(4, 3.14159) # Tag 4: float

541

writer.put_bytes(5, b"binary_data") # Tag 5: byte string

542

543

# Get the encoded TLV data

544

tlv_data = writer.finalize()

545

print(f"Encoded TLV data: {len(tlv_data)} bytes")

546

547

# Create a TLV reader to decode the data

548

reader = TLVReader(tlv_data)

549

550

# Read values by tag

551

int_value = reader.get_int(1)

552

string_value = reader.get_string(2)

553

bool_value = reader.get_bool(3)

554

float_value = reader.get_float(4)

555

bytes_value = reader.get_bytes(5)

556

557

print(f"Integer: {int_value}")

558

print(f"String: {string_value}")

559

print(f"Boolean: {bool_value}")

560

print(f"Float: {float_value}")

561

print(f"Bytes: {bytes_value}")

562

563

# Get all values at once

564

all_values = reader.get_all()

565

print(f"All values: {all_values}")

566

```

567

568

### TLV Containers (Structures and Arrays)

569

570

```python

571

from chip.tlv import TLVWriter, TLVReader

572

573

# Create writer for structured data

574

writer = TLVWriter()

575

576

# Start a structure container

577

writer.start_container(1, 0) # Tag 1, type 0 (Structure)

578

579

# Add fields to the structure

580

writer.put_string(1, "Device Name") # Device name

581

writer.put_int(2, 0x1234) # Vendor ID

582

writer.put_int(3, 0x5678) # Product ID

583

584

# Start an array of endpoints

585

writer.start_container(4, 1) # Tag 4, type 1 (Array)

586

writer.put_int(0, 0) # Endpoint 0

587

writer.put_int(1, 1) # Endpoint 1

588

writer.put_int(2, 2) # Endpoint 2

589

writer.end_container() # End endpoints array

590

591

# End the main structure

592

writer.end_container()

593

594

# Get encoded data

595

tlv_data = writer.finalize()

596

print(f"Structured TLV data: {len(tlv_data)} bytes")

597

598

# Read the structured data

599

reader = TLVReader(tlv_data)

600

601

# Get the main structure

602

main_struct = reader.get_container(1)

603

if main_struct:

604

device_name = main_struct.get_string(1)

605

vendor_id = main_struct.get_int(2)

606

product_id = main_struct.get_int(3)

607

608

print(f"Device: {device_name}")

609

print(f"Vendor ID: 0x{vendor_id:04X}")

610

print(f"Product ID: 0x{product_id:04X}")

611

612

# Get the endpoints array

613

endpoints_array = main_struct.get_container(4)

614

if endpoints_array:

615

all_endpoints = endpoints_array.get_all()

616

endpoints = [all_endpoints[tag] for tag in sorted(all_endpoints.keys())]

617

print(f"Endpoints: {endpoints}")

618

```

619

620

### Matter Cluster Data Encoding

621

622

```python

623

from chip.tlv import TLVWriter, TLVReader

624

import chip.clusters as Clusters

625

626

# Encode OnOff cluster command

627

writer = TLVWriter()

628

629

# OnOff On command (no parameters)

630

writer.start_container(1, 0) # Command structure

631

writer.end_container()

632

633

on_command_tlv = writer.finalize()

634

635

# Encode LevelControl MoveToLevel command with parameters

636

writer = TLVWriter()

637

writer.start_container(1, 0) # Command structure

638

writer.put_int(0, 128) # Level (0-254)

639

writer.put_int(1, 10) # Transition time (1/10 seconds)

640

writer.put_int(2, 0) # Options mask

641

writer.put_int(3, 0) # Options override

642

writer.end_container()

643

644

level_command_tlv = writer.finalize()

645

646

print(f"OnOff command TLV: {len(on_command_tlv)} bytes")

647

print(f"LevelControl command TLV: {len(level_command_tlv)} bytes")

648

649

# Decode level control command

650

reader = TLVReader(level_command_tlv)

651

command_struct = reader.get_container(1)

652

if command_struct:

653

level = command_struct.get_int(0)

654

transition_time = command_struct.get_int(1)

655

options_mask = command_struct.get_int(2)

656

options_override = command_struct.get_int(3)

657

658

print(f"Decoded MoveToLevel command:")

659

print(f" Level: {level}")

660

print(f" Transition time: {transition_time/10.0}s")

661

print(f" Options mask: {options_mask}")

662

print(f" Options override: {options_override}")

663

```

664

665

### TLV Utilities and Type Handling

666

667

```python

668

from chip.tlv import TLVUtils, float32, uint, int

669

670

# Convert Python data to TLV

671

python_data = {

672

"device_info": {

673

"name": "Smart Light",

674

"endpoints": [0, 1],

675

"active": True,

676

"temperature": 23.5

677

},

678

"settings": {

679

"brightness": 75,

680

"color_temp": 2700

681

}

682

}

683

684

# Convert to TLV

685

tlv_bytes = TLVUtils.python_to_tlv(python_data)

686

print(f"Python to TLV: {len(tlv_bytes)} bytes")

687

688

# Convert back to Python

689

decoded_data = TLVUtils.tlv_to_python(tlv_bytes)

690

print(f"TLV to Python: {decoded_data}")

691

692

# Validate TLV data

693

is_valid = TLVUtils.validate_tlv(tlv_bytes)

694

print(f"TLV is valid: {is_valid}")

695

696

# Pretty print TLV structure

697

pretty_output = TLVUtils.pretty_print_tlv(tlv_bytes)

698

print("TLV Structure:")

699

print(pretty_output)

700

701

# Use specific TLV types

702

writer = TLVWriter()

703

704

# Use 32-bit float specifically

705

writer.put(1, float32(3.14159))

706

707

# Use unsigned integer with specific size

708

writer.put(2, uint(65535, size=2)) # 16-bit unsigned int

709

710

# Use signed integer with specific size

711

writer.put(3, int(-32768, size=2)) # 16-bit signed int

712

713

typed_tlv_data = writer.finalize()

714

715

# Read with type information preserved

716

reader = TLVReader(typed_tlv_data)

717

float_val = reader.get_float(1)

718

uint_val = reader.get_uint(2)

719

int_val = reader.get_int(3)

720

721

print(f"32-bit float: {float_val}")

722

print(f"16-bit uint: {uint_val}")

723

print(f"16-bit int: {int_val}")

724

```

725

726

### Custom TLV Tag Encoding

727

728

```python

729

from chip.tlv import TLVWriter, TLVReader, TLVUtils

730

731

# Create custom tags using profile IDs

732

writer = TLVWriter()

733

734

# Standard Matter tags (profile 0)

735

standard_tag = TLVUtils.encode_tag(0, 1) # Profile 0, tag 1

736

writer.put_string(standard_tag, "Standard tag")

737

738

# Vendor-specific tags (custom profile)

739

vendor_profile = 0x1234

740

vendor_tag = TLVUtils.encode_tag(vendor_profile, 100)

741

writer.put_int(vendor_tag, 42)

742

743

# Context-specific tags

744

context_tag = TLVUtils.encode_tag(0, 1, is_context_specific=True)

745

writer.put_bool(context_tag, True)

746

747

custom_tlv_data = writer.finalize()

748

749

# Read and decode tag information

750

reader = TLVReader(custom_tlv_data)

751

all_data = reader.get_all()

752

753

for tag, value in all_data.items():

754

tag_info = TLVUtils.decode_tag(tag)

755

print(f"Tag {tag}: Profile {tag_info['profile_id']}, "

756

f"Number {tag_info['tag_num']}, "

757

f"Context-specific: {tag_info['is_context_specific']}, "

758

f"Value: {value}")

759

```

760

761

### Integration with Matter Device Communication

762

763

```python

764

from chip.tlv import TLVWriter, TLVReader

765

from chip.ChipDeviceCtrl import ChipDeviceController

766

import chip.clusters as Clusters

767

768

# Initialize controller

769

controller = ChipDeviceController(controllerNodeId=12345)

770

771

# Example: Create custom attribute write using TLV

772

writer = TLVWriter()

773

774

# Encode attribute write request

775

writer.start_container(1, 0) # AttributeWriteRequest structure

776

777

# Attribute path

778

writer.start_container(1, 0) # AttributePath

779

writer.put_int(1, 1) # Endpoint

780

writer.put_int(2, 6) # Cluster ID (OnOff)

781

writer.put_int(3, 0) # Attribute ID (OnOff)

782

writer.end_container()

783

784

# Attribute value

785

writer.put_bool(2, True) # Turn on

786

787

writer.end_container()

788

789

write_request_tlv = writer.finalize()

790

791

# In practice, this TLV would be sent as part of a Matter message

792

print(f"Custom attribute write TLV: {len(write_request_tlv)} bytes")

793

794

# Example: Parse attribute read response TLV

795

# (This would typically come from a device response)

796

response_tlv = b"..." # Simulated response data

797

798

try:

799

reader = TLVReader(response_tlv)

800

801

# Parse attribute read response structure

802

if reader.has_tag(1): # Success response

803

attr_data = reader.get_container(1)

804

if attr_data:

805

# Extract attribute path and value

806

path = attr_data.get_container(1)

807

value = attr_data.get(2)

808

809

if path:

810

endpoint = path.get_int(1)

811

cluster = path.get_int(2)

812

attribute = path.get_int(3)

813

814

print(f"Attribute read response:")

815

print(f" Endpoint: {endpoint}")

816

print(f" Cluster: {cluster}")

817

print(f" Attribute: {attribute}")

818

print(f" Value: {value}")

819

820

elif reader.has_tag(2): # Error response

821

error_code = reader.get_int(2)

822

print(f"Attribute read failed with error: {error_code}")

823

824

except Exception as e:

825

print(f"Failed to parse TLV response: {e}")

826

827

# Clean up

828

controller.Shutdown()

829

```