or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

device-shadow.mdfleet-provisioning.mdgreengrass-discovery.mdgreengrass-ipc.mdindex.mdiot-jobs.mdmqtt-connections.md

device-shadow.mddocs/

0

# Device Shadow Operations

1

2

Complete AWS IoT Device Shadow functionality including get, update, delete operations for both classic and named shadows, with support for shadow delta events and real-time shadow document updates through both V1 (callback-based) and V2 (Future-based) client interfaces.

3

4

## Capabilities

5

6

### V1 Shadow Client (Callback-Based)

7

8

The V1 client provides callback-based operations following the traditional publish/subscribe pattern.

9

10

#### Client Creation

11

12

```python { .api }

13

class IotShadowClient(MqttServiceClient):

14

"""

15

V1 client for AWS IoT Device Shadow service with callback-based operations.

16

17

Parameters:

18

- mqtt_connection: MQTT connection (mqtt.Connection or mqtt5.Client)

19

"""

20

def __init__(self, mqtt_connection): ...

21

```

22

23

Usage example:

24

25

```python

26

from awsiot import mqtt_connection_builder, iotshadow

27

28

# Create MQTT connection

29

connection = mqtt_connection_builder.mtls_from_path(

30

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

31

cert_filepath="/path/to/certificate.pem.crt",

32

pri_key_filepath="/path/to/private.pem.key",

33

client_id="shadow-client-123"

34

)

35

36

# Create shadow client

37

shadow_client = iotshadow.IotShadowClient(connection)

38

```

39

40

#### Classic Shadow Operations

41

42

##### Get Shadow

43

44

```python { .api }

45

def publish_get_shadow(self, request, qos):

46

"""

47

Publish request to get device shadow.

48

49

Parameters:

50

- request (GetShadowRequest): Shadow request

51

- qos (awscrt.mqtt.QoS): Quality of service

52

53

Returns:

54

Future: Future that completes when request is published

55

"""

56

57

def subscribe_to_get_shadow_accepted(self, request, qos, callback):

58

"""

59

Subscribe to successful get shadow responses.

60

61

Parameters:

62

- request (GetShadowSubscriptionRequest): Subscription request

63

- qos (awscrt.mqtt.QoS): Quality of service

64

- callback: Function called when shadow is retrieved

65

66

Returns:

67

Tuple[Future, str]: Future for subscription, topic string

68

"""

69

70

def subscribe_to_get_shadow_rejected(self, request, qos, callback):

71

"""

72

Subscribe to rejected get shadow responses.

73

74

Parameters:

75

- request (GetShadowSubscriptionRequest): Subscription request

76

- qos (awscrt.mqtt.QoS): Quality of service

77

- callback: Function called when request is rejected

78

79

Returns:

80

Tuple[Future, str]: Future for subscription, topic string

81

"""

82

```

83

84

##### Update Shadow

85

86

```python { .api }

87

def publish_update_shadow(self, request, qos):

88

"""

89

Publish request to update device shadow.

90

91

Parameters:

92

- request (UpdateShadowRequest): Shadow update request

93

- qos (awscrt.mqtt.QoS): Quality of service

94

95

Returns:

96

Future: Future that completes when request is published

97

"""

98

99

def subscribe_to_update_shadow_accepted(self, request, qos, callback):

100

"""

101

Subscribe to successful update shadow responses.

102

103

Parameters:

104

- request (UpdateShadowSubscriptionRequest): Subscription request

105

- qos (awscrt.mqtt.QoS): Quality of service

106

- callback: Function called when update succeeds

107

108

Returns:

109

Tuple[Future, str]: Future for subscription, topic string

110

"""

111

112

def subscribe_to_update_shadow_rejected(self, request, qos, callback):

113

"""

114

Subscribe to rejected update shadow responses.

115

116

Parameters:

117

- request (UpdateShadowSubscriptionRequest): Subscription request

118

- qos (awscrt.mqtt.QoS): Quality of service

119

- callback: Function called when update is rejected

120

121

Returns:

122

Tuple[Future, str]: Future for subscription, topic string

123

"""

124

```

125

126

##### Delete Shadow

127

128

```python { .api }

129

def publish_delete_shadow(self, request, qos):

130

"""

131

Publish request to delete device shadow.

132

133

Parameters:

134

- request (DeleteShadowRequest): Shadow delete request

135

- qos (awscrt.mqtt.QoS): Quality of service

136

137

Returns:

138

Future: Future that completes when request is published

139

"""

140

141

def subscribe_to_delete_shadow_accepted(self, request, qos, callback):

142

"""

143

Subscribe to successful delete shadow responses.

144

"""

145

146

def subscribe_to_delete_shadow_rejected(self, request, qos, callback):

147

"""

148

Subscribe to rejected delete shadow responses.

149

"""

150

```

151

152

#### Named Shadow Operations

153

154

Named shadows allow multiple shadows per device. All classic shadow operations have named shadow equivalents:

155

156

```python { .api }

157

def publish_get_named_shadow(self, request, qos): ...

158

def publish_update_named_shadow(self, request, qos): ...

159

def publish_delete_named_shadow(self, request, qos): ...

160

161

def subscribe_to_get_named_shadow_accepted(self, request, qos, callback): ...

162

def subscribe_to_get_named_shadow_rejected(self, request, qos, callback): ...

163

def subscribe_to_update_named_shadow_accepted(self, request, qos, callback): ...

164

def subscribe_to_update_named_shadow_rejected(self, request, qos, callback): ...

165

def subscribe_to_delete_named_shadow_accepted(self, request, qos, callback): ...

166

def subscribe_to_delete_named_shadow_rejected(self, request, qos, callback): ...

167

```

168

169

#### Shadow Event Subscriptions

170

171

##### Delta Events

172

173

Subscribe to shadow delta events when desired and reported states differ:

174

175

```python { .api }

176

def subscribe_to_shadow_delta_events(self, request, qos, callback):

177

"""

178

Subscribe to shadow delta events for classic shadow.

179

180

Parameters:

181

- request (ShadowDeltaUpdatedSubscriptionRequest): Subscription request

182

- qos (awscrt.mqtt.QoS): Quality of service

183

- callback: Function called when delta event occurs

184

185

Returns:

186

Tuple[Future, str]: Future for subscription, topic string

187

"""

188

189

def subscribe_to_named_shadow_delta_events(self, request, qos, callback):

190

"""

191

Subscribe to shadow delta events for named shadow.

192

"""

193

```

194

195

##### Document Events

196

197

Subscribe to shadow document update events:

198

199

```python { .api }

200

def subscribe_to_shadow_documents_events(self, request, qos, callback):

201

"""

202

Subscribe to shadow document update events for classic shadow.

203

204

Parameters:

205

- request (ShadowUpdatedSubscriptionRequest): Subscription request

206

- qos (awscrt.mqtt.QoS): Quality of service

207

- callback: Function called when shadow document updates

208

209

Returns:

210

Tuple[Future, str]: Future for subscription, topic string

211

"""

212

213

def subscribe_to_named_shadow_documents_events(self, request, qos, callback):

214

"""

215

Subscribe to shadow document update events for named shadow.

216

"""

217

```

218

219

### V2 Shadow Client (Future-Based)

220

221

The V2 client provides Future-based operations with request-response semantics.

222

223

#### Client Creation

224

225

```python { .api }

226

class IotShadowClientV2:

227

"""

228

V2 client for AWS IoT Device Shadow service with Future-based operations.

229

"""

230

def __init__(self, connection): ...

231

```

232

233

#### Classic Shadow Operations

234

235

```python { .api }

236

def get_shadow(self, request):

237

"""

238

Get device shadow using request-response pattern.

239

240

Parameters:

241

- request (GetShadowRequest): Shadow request

242

243

Returns:

244

Future[GetShadowResponse]: Future containing shadow response

245

"""

246

247

def update_shadow(self, request):

248

"""

249

Update device shadow using request-response pattern.

250

251

Parameters:

252

- request (UpdateShadowRequest): Shadow update request

253

254

Returns:

255

Future[UpdateShadowResponse]: Future containing update response

256

"""

257

258

def delete_shadow(self, request):

259

"""

260

Delete device shadow using request-response pattern.

261

262

Parameters:

263

- request (DeleteShadowRequest): Shadow delete request

264

265

Returns:

266

Future[DeleteShadowResponse]: Future containing delete response

267

"""

268

```

269

270

#### Named Shadow Operations

271

272

```python { .api }

273

def get_named_shadow(self, request):

274

"""Get named shadow using request-response pattern."""

275

276

def update_named_shadow(self, request):

277

"""Update named shadow using request-response pattern."""

278

279

def delete_named_shadow(self, request):

280

"""Delete named shadow using request-response pattern."""

281

```

282

283

#### Streaming Operations

284

285

```python { .api }

286

def create_shadow_delta_stream(self, request, options):

287

"""

288

Create streaming operation for shadow delta events.

289

290

Parameters:

291

- request (ShadowDeltaUpdatedSubscriptionRequest): Stream request

292

- options (ServiceStreamOptions): Stream configuration

293

294

Returns:

295

StreamingOperation: Streaming operation handle

296

"""

297

298

def create_named_shadow_delta_stream(self, request, options):

299

"""Create streaming operation for named shadow delta events."""

300

301

def create_shadow_documents_stream(self, request, options):

302

"""Create streaming operation for shadow document events."""

303

304

def create_named_shadow_documents_stream(self, request, options):

305

"""Create streaming operation for named shadow document events."""

306

```

307

308

### Data Model Classes

309

310

#### Request Classes

311

312

```python { .api }

313

@dataclass

314

class GetShadowRequest:

315

"""Request to get device shadow."""

316

thing_name: str

317

318

@dataclass

319

class GetNamedShadowRequest:

320

"""Request to get named shadow."""

321

thing_name: str

322

shadow_name: str

323

324

@dataclass

325

class UpdateShadowRequest:

326

"""Request to update device shadow."""

327

thing_name: str

328

state: Optional[ShadowState] = None

329

client_token: Optional[str] = None

330

331

@dataclass

332

class UpdateNamedShadowRequest:

333

"""Request to update named shadow."""

334

thing_name: str

335

shadow_name: str

336

state: Optional[ShadowState] = None

337

client_token: Optional[str] = None

338

339

@dataclass

340

class DeleteShadowRequest:

341

"""Request to delete device shadow."""

342

thing_name: str

343

344

@dataclass

345

class DeleteNamedShadowRequest:

346

"""Request to delete named shadow."""

347

thing_name: str

348

shadow_name: str

349

```

350

351

#### Response Classes

352

353

```python { .api }

354

@dataclass

355

class GetShadowResponse:

356

"""Response from get shadow operation."""

357

state: Optional[ShadowStateWithDelta] = None

358

metadata: Optional[ShadowMetadata] = None

359

version: Optional[int] = None

360

timestamp: Optional[datetime.datetime] = None

361

client_token: Optional[str] = None

362

363

@dataclass

364

class UpdateShadowResponse:

365

"""Response from update shadow operation."""

366

state: Optional[ShadowState] = None

367

metadata: Optional[ShadowMetadata] = None

368

version: Optional[int] = None

369

timestamp: Optional[datetime.datetime] = None

370

client_token: Optional[str] = None

371

372

@dataclass

373

class DeleteShadowResponse:

374

"""Response from delete shadow operation."""

375

version: Optional[int] = None

376

timestamp: Optional[datetime.datetime] = None

377

client_token: Optional[str] = None

378

```

379

380

#### Shadow State Classes

381

382

```python { .api }

383

@dataclass

384

class ShadowState:

385

"""Device shadow state containing desired and reported properties."""

386

desired: Optional[Dict[str, Any]] = None

387

reported: Optional[Dict[str, Any]] = None

388

389

@dataclass

390

class ShadowStateWithDelta:

391

"""Shadow state including delta between desired and reported."""

392

desired: Optional[Dict[str, Any]] = None

393

reported: Optional[Dict[str, Any]] = None

394

delta: Optional[Dict[str, Any]] = None

395

396

@dataclass

397

class ShadowMetadata:

398

"""Metadata about shadow properties including timestamps."""

399

desired: Optional[Dict[str, Any]] = None

400

reported: Optional[Dict[str, Any]] = None

401

```

402

403

#### Event Classes

404

405

```python { .api }

406

@dataclass

407

class ShadowDeltaUpdatedEvent:

408

"""Event published when shadow delta changes."""

409

version: Optional[int] = None

410

timestamp: Optional[datetime.datetime] = None

411

state: Optional[Dict[str, Any]] = None

412

metadata: Optional[Dict[str, Any]] = None

413

client_token: Optional[str] = None

414

415

@dataclass

416

class ShadowUpdatedEvent:

417

"""Event published when shadow document updates."""

418

previous: Optional[ShadowUpdatedSnapshot] = None

419

current: Optional[ShadowUpdatedSnapshot] = None

420

timestamp: Optional[datetime.datetime] = None

421

client_token: Optional[str] = None

422

```

423

424

#### Subscription Request Classes

425

426

```python { .api }

427

@dataclass

428

class GetShadowSubscriptionRequest:

429

"""Subscription request for get shadow responses."""

430

thing_name: str

431

432

@dataclass

433

class ShadowDeltaUpdatedSubscriptionRequest:

434

"""Subscription request for shadow delta events."""

435

thing_name: str

436

437

@dataclass

438

class ShadowUpdatedSubscriptionRequest:

439

"""Subscription request for shadow document events."""

440

thing_name: str

441

```

442

443

#### Error Response Classes

444

445

```python { .api }

446

@dataclass

447

class ErrorResponse:

448

"""Error response from shadow operations."""

449

code: Optional[int] = None

450

message: Optional[str] = None

451

timestamp: Optional[datetime.datetime] = None

452

client_token: Optional[str] = None

453

```

454

455

## Usage Examples

456

457

### V1 Client - Basic Shadow Update

458

459

```python

460

from awsiot import mqtt_connection_builder, iotshadow

461

from awscrt import mqtt

462

import json

463

464

# Create connection and client

465

connection = mqtt_connection_builder.mtls_from_path(

466

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

467

cert_filepath="/path/to/certificate.pem.crt",

468

pri_key_filepath="/path/to/private.pem.key",

469

client_id="shadow-device-123"

470

)

471

472

shadow_client = iotshadow.IotShadowClient(connection)

473

connection.connect().result()

474

475

# Define callbacks

476

def on_update_accepted(response):

477

print(f"Shadow update accepted: {response}")

478

479

def on_update_rejected(error):

480

print(f"Shadow update rejected: {error}")

481

482

# Subscribe to responses

483

shadow_client.subscribe_to_update_shadow_accepted(

484

iotshadow.UpdateShadowSubscriptionRequest(thing_name="MyDevice"),

485

mqtt.QoS.AT_LEAST_ONCE,

486

on_update_accepted

487

).result()

488

489

shadow_client.subscribe_to_update_shadow_rejected(

490

iotshadow.UpdateShadowSubscriptionRequest(thing_name="MyDevice"),

491

mqtt.QoS.AT_LEAST_ONCE,

492

on_update_rejected

493

).result()

494

495

# Update shadow

496

update_request = iotshadow.UpdateShadowRequest(

497

thing_name="MyDevice",

498

state=iotshadow.ShadowState(

499

reported={"temperature": 23.5, "humidity": 60.2, "status": "online"}

500

)

501

)

502

503

shadow_client.publish_update_shadow(update_request, mqtt.QoS.AT_LEAST_ONCE).result()

504

```

505

506

### V1 Client - Shadow Delta Monitoring

507

508

```python

509

def on_shadow_delta(delta_event):

510

"""Handle shadow delta events when desired != reported."""

511

print(f"Shadow delta received: {delta_event}")

512

513

# Extract delta changes

514

if delta_event.state:

515

for property_name, desired_value in delta_event.state.items():

516

print(f"Property '{property_name}' should be updated to: {desired_value}")

517

518

# Update device state and report back

519

# ... device-specific logic here ...

520

521

# Report updated state

522

update_request = iotshadow.UpdateShadowRequest(

523

thing_name="MyDevice",

524

state=iotshadow.ShadowState(

525

reported=delta_event.state # Report desired state as achieved

526

),

527

client_token=delta_event.client_token

528

)

529

shadow_client.publish_update_shadow(update_request, mqtt.QoS.AT_LEAST_ONCE)

530

531

# Subscribe to delta events

532

shadow_client.subscribe_to_shadow_delta_events(

533

iotshadow.ShadowDeltaUpdatedSubscriptionRequest(thing_name="MyDevice"),

534

mqtt.QoS.AT_LEAST_ONCE,

535

on_shadow_delta

536

).result()

537

```

538

539

### V2 Client - Request-Response Pattern

540

541

```python

542

from awsiot import mqtt_connection_builder, iotshadow

543

import asyncio

544

545

async def shadow_operations():

546

# Create connection

547

connection = mqtt_connection_builder.mtls_from_path(

548

endpoint="your-endpoint.iot.us-east-1.amazonaws.com",

549

cert_filepath="/path/to/certificate.pem.crt",

550

pri_key_filepath="/path/to/private.pem.key",

551

client_id="shadow-v2-client"

552

)

553

554

# Create V2 client

555

shadow_client = iotshadow.IotShadowClientV2(connection)

556

await connection.connect()

557

558

try:

559

# Get current shadow

560

get_request = iotshadow.GetShadowRequest(thing_name="MyDevice")

561

get_response = await shadow_client.get_shadow(get_request)

562

print(f"Current shadow: {get_response}")

563

564

# Update shadow

565

update_request = iotshadow.UpdateShadowRequest(

566

thing_name="MyDevice",

567

state=iotshadow.ShadowState(

568

desired={"target_temperature": 22.0},

569

reported={"current_temperature": 20.1}

570

)

571

)

572

update_response = await shadow_client.update_shadow(update_request)

573

print(f"Update response: {update_response}")

574

575

except iotshadow.V2ServiceException as e:

576

print(f"Shadow operation failed: {e.message}")

577

if e.modeled_error:

578

print(f"Error details: {e.modeled_error}")

579

580

finally:

581

await connection.disconnect()

582

583

# Run async operations

584

asyncio.run(shadow_operations())

585

```

586

587

### Named Shadow Operations

588

589

```python

590

# Using named shadows for multi-component devices

591

update_request = iotshadow.UpdateNamedShadowRequest(

592

thing_name="SmartHome",

593

shadow_name="thermostat",

594

state=iotshadow.ShadowState(

595

reported={

596

"temperature": 21.5,

597

"humidity": 45.0,

598

"mode": "heat",

599

"target_temperature": 22.0

600

}

601

)

602

)

603

604

# V1 client

605

shadow_client.publish_update_named_shadow(update_request, mqtt.QoS.AT_LEAST_ONCE)

606

607

# V2 client

608

response = await shadow_client.update_named_shadow(update_request)

609

```