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

greengrass-discovery.mddocs/

0

# Greengrass Discovery

1

2

Greengrass Core discovery functionality for edge computing scenarios including connectivity information retrieval and core device discovery for local communication setup in AWS IoT Greengrass environments.

3

4

## Capabilities

5

6

### Discovery Client

7

8

The DiscoveryClient enables devices to discover nearby Greengrass Core devices and their connectivity information for local communication.

9

10

#### Client Creation

11

12

```python { .api }

13

class DiscoveryClient:

14

"""

15

Client for Greengrass discovery operations.

16

17

Parameters:

18

- bootstrap: Client bootstrap for networking

19

- socket_options: TCP socket options

20

- tls_context: TLS context for secure connection

21

- region (str): AWS region

22

- gg_server_name (str): Greengrass server name (optional)

23

- proxy_options: HTTP proxy options (optional)

24

"""

25

def __init__(self, bootstrap, socket_options, tls_context, region, gg_server_name=None, proxy_options=None): ...

26

```

27

28

#### Discovery Operations

29

30

```python { .api }

31

def discover(self, thing_name):

32

"""

33

Discover Greengrass Core devices for the specified thing.

34

35

Parameters:

36

- thing_name (str): Name of the IoT thing to discover cores for

37

38

Returns:

39

Future[DiscoverResponse]: Future containing discovery response with core information

40

"""

41

```

42

43

### Data Model Classes

44

45

#### Discovery Response

46

47

```python { .api }

48

@dataclass

49

class DiscoverResponse:

50

"""

51

Response from Greengrass discovery operation containing core information.

52

"""

53

gg_groups: Optional[List[GGGroup]] = None

54

```

55

56

#### Greengrass Group

57

58

```python { .api }

59

@dataclass

60

class GGGroup:

61

"""

62

Greengrass group containing core devices and their connectivity information.

63

"""

64

gg_group_id: Optional[str] = None

65

cores: Optional[List[GGCore]] = None

66

certificate_authorities: Optional[List[str]] = None

67

```

68

69

#### Greengrass Core

70

71

```python { .api }

72

@dataclass

73

class GGCore:

74

"""

75

Greengrass Core device with connectivity endpoints.

76

"""

77

thing_arn: Optional[str] = None

78

connectivity: Optional[List[ConnectivityInfo]] = None

79

```

80

81

#### Connectivity Information

82

83

```python { .api }

84

@dataclass

85

class ConnectivityInfo:

86

"""

87

Connectivity information for reaching a Greengrass Core.

88

"""

89

id: Optional[str] = None

90

host_address: Optional[str] = None

91

port: Optional[int] = None

92

metadata: Optional[str] = None

93

```

94

95

#### Exception Classes

96

97

```python { .api }

98

class DiscoveryException(Exception):

99

"""

100

Exception raised during Greengrass discovery operations.

101

102

Attributes:

103

- message (str): Error message

104

- status_code (int): HTTP status code from discovery service

105

"""

106

def __init__(self, message, status_code=None): ...

107

```

108

109

## Usage Examples

110

111

### Basic Discovery

112

113

```python

114

from awsiot import greengrass_discovery

115

from awscrt import io, auth, http, mqtt

116

import json

117

118

# Create event loop group and host resolver

119

event_loop_group = io.EventLoopGroup(1)

120

host_resolver = io.DefaultHostResolver(event_loop_group)

121

122

# Create client bootstrap

123

client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver)

124

125

# Create socket options

126

socket_options = io.SocketOptions()

127

128

# Create TLS context with device certificate

129

tls_context_options = io.TlsContextOptions.create_client_with_mtls_from_path(

130

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

131

pri_key_filepath="/path/to/device-private.pem.key"

132

)

133

tls_context = io.ClientTlsContext(tls_context_options)

134

135

# Create discovery client

136

discovery_client = greengrass_discovery.DiscoveryClient(

137

bootstrap=client_bootstrap,

138

socket_options=socket_options,

139

tls_context=tls_context,

140

region="us-east-1"

141

)

142

143

def discover_cores(thing_name):

144

"""Discover Greengrass cores for a device."""

145

try:

146

print(f"Discovering Greengrass cores for thing: {thing_name}")

147

148

# Perform discovery

149

discover_future = discovery_client.discover(thing_name)

150

discover_response = discover_future.result(timeout=30)

151

152

print(f"Discovery successful! Found {len(discover_response.gg_groups)} groups")

153

154

for group in discover_response.gg_groups:

155

print(f"\nGroup ID: {group.gg_group_id}")

156

print(f"Certificate Authorities: {len(group.certificate_authorities)}")

157

158

for i, ca_pem in enumerate(group.certificate_authorities):

159

# Save CA certificates for later use

160

with open(f"/tmp/gg-ca-{i}.pem", "w") as f:

161

f.write(ca_pem)

162

print(f" Saved CA certificate {i} to /tmp/gg-ca-{i}.pem")

163

164

print(f"Cores: {len(group.cores)}")

165

for core in group.cores:

166

print(f" Core ARN: {core.thing_arn}")

167

print(f" Connectivity options: {len(core.connectivity)}")

168

169

for conn in core.connectivity:

170

print(f" ID: {conn.id}")

171

print(f" Host: {conn.host_address}:{conn.port}")

172

if conn.metadata:

173

print(f" Metadata: {conn.metadata}")

174

175

return discover_response

176

177

except greengrass_discovery.DiscoveryException as e:

178

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

179

if e.status_code:

180

print(f"Status code: {e.status_code}")

181

return None

182

except Exception as e:

183

print(f"Discovery error: {e}")

184

return None

185

186

# Discover cores

187

discovery_response = discover_cores("MyGreengrassDevice")

188

```

189

190

### Connect to Discovered Core

191

192

```python

193

from awsiot import greengrass_discovery, mqtt_connection_builder

194

from awscrt import io, mqtt

195

import json

196

197

def connect_to_greengrass_core(thing_name):

198

"""Discover and connect to a Greengrass core."""

199

200

# Perform discovery

201

event_loop_group = io.EventLoopGroup(1)

202

host_resolver = io.DefaultHostResolver(event_loop_group)

203

client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver)

204

socket_options = io.SocketOptions()

205

206

tls_context_options = io.TlsContextOptions.create_client_with_mtls_from_path(

207

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

208

pri_key_filepath="/path/to/device-private.pem.key"

209

)

210

tls_context = io.ClientTlsContext(tls_context_options)

211

212

discovery_client = greengrass_discovery.DiscoveryClient(

213

bootstrap=client_bootstrap,

214

socket_options=socket_options,

215

tls_context=tls_context,

216

region="us-east-1"

217

)

218

219

try:

220

# Discover cores

221

discover_future = discovery_client.discover(thing_name)

222

discover_response = discover_future.result(timeout=30)

223

224

if not discover_response.gg_groups:

225

print("No Greengrass groups found")

226

return None

227

228

# Try to connect to the first available core

229

for group in discover_response.gg_groups:

230

if not group.cores:

231

continue

232

233

# Save CA certificates

234

ca_filepath = "/tmp/gg-ca.pem"

235

with open(ca_filepath, "w") as f:

236

for ca_pem in group.certificate_authorities:

237

f.write(ca_pem)

238

239

for core in group.cores:

240

if not core.connectivity:

241

continue

242

243

# Try each connectivity option

244

for conn_info in core.connectivity:

245

try:

246

print(f"Attempting connection to {conn_info.host_address}:{conn_info.port}")

247

248

# Create MQTT connection to Greengrass core

249

connection = mqtt_connection_builder.mtls_from_path(

250

endpoint=conn_info.host_address,

251

port=conn_info.port,

252

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

253

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

254

ca_filepath=ca_filepath,

255

client_id=thing_name,

256

clean_session=False,

257

keep_alive_secs=30

258

)

259

260

# Connect

261

connect_future = connection.connect()

262

connect_future.result(timeout=10)

263

264

print(f"Successfully connected to Greengrass core at {conn_info.host_address}:{conn_info.port}")

265

266

# Test communication

267

test_communication(connection, thing_name)

268

269

# Disconnect

270

disconnect_future = connection.disconnect()

271

disconnect_future.result()

272

273

return connection

274

275

except Exception as e:

276

print(f"Failed to connect to {conn_info.host_address}:{conn_info.port}: {e}")

277

continue

278

279

print("Failed to connect to any discovered Greengrass cores")

280

return None

281

282

except Exception as e:

283

print(f"Discovery and connection failed: {e}")

284

return None

285

286

def test_communication(connection, thing_name):

287

"""Test communication with Greengrass core."""

288

289

def on_message_received(topic, payload, dup, qos, retain, **kwargs):

290

print(f"Received message on topic {topic}: {payload.decode()}")

291

292

# Subscribe to a local topic

293

local_topic = f"greengrass/device/{thing_name}/data"

294

subscribe_future, _ = connection.subscribe(

295

topic=local_topic,

296

qos=mqtt.QoS.AT_LEAST_ONCE,

297

callback=on_message_received

298

)

299

subscribe_future.result()

300

301

# Publish a test message

302

test_message = {

303

"device_id": thing_name,

304

"message": "Hello from device!",

305

"timestamp": "2023-12-07T10:30:00Z"

306

}

307

308

publish_future, _ = connection.publish(

309

topic=local_topic,

310

payload=json.dumps(test_message),

311

qos=mqtt.QoS.AT_LEAST_ONCE

312

)

313

publish_future.result()

314

315

print("Test message published to Greengrass core")

316

317

# Connect to Greengrass core

318

connection = connect_to_greengrass_core("MyGreengrassDevice")

319

```

320

321

### Discovery with Connection Fallback

322

323

```python

324

from awsiot import greengrass_discovery, mqtt_connection_builder

325

import time

326

327

class GreengrassConnector:

328

def __init__(self, thing_name, cert_path, key_path, region):

329

self.thing_name = thing_name

330

self.cert_path = cert_path

331

self.key_path = key_path

332

self.region = region

333

self.current_connection = None

334

self.discovered_cores = []

335

336

def discover_and_connect(self):

337

"""Discover cores and establish connection with fallback."""

338

339

# Perform discovery

340

discovery_response = self._discover_cores()

341

if not discovery_response:

342

return False

343

344

# Extract all connectivity options

345

self.discovered_cores = []

346

for group in discovery_response.gg_groups:

347

# Save CA certificates

348

ca_filepath = f"/tmp/gg-ca-{group.gg_group_id}.pem"

349

with open(ca_filepath, "w") as f:

350

for ca_pem in group.certificate_authorities:

351

f.write(ca_pem)

352

353

for core in group.cores:

354

for conn_info in core.connectivity:

355

self.discovered_cores.append({

356

'host': conn_info.host_address,

357

'port': conn_info.port,

358

'ca_file': ca_filepath,

359

'core_arn': core.thing_arn,

360

'group_id': group.gg_group_id

361

})

362

363

# Sort by preference (you can implement your own logic)

364

self.discovered_cores.sort(key=lambda x: x['port']) # Prefer certain ports

365

366

# Try to connect to cores in order

367

for core_info in self.discovered_cores:

368

if self._try_connect(core_info):

369

return True

370

371

print("Failed to connect to any discovered Greengrass cores")

372

return False

373

374

def _discover_cores(self):

375

"""Perform Greengrass discovery."""

376

try:

377

# Setup discovery client

378

event_loop_group = io.EventLoopGroup(1)

379

host_resolver = io.DefaultHostResolver(event_loop_group)

380

client_bootstrap = io.ClientBootstrap(event_loop_group, host_resolver)

381

socket_options = io.SocketOptions()

382

383

tls_context_options = io.TlsContextOptions.create_client_with_mtls_from_path(

384

cert_filepath=self.cert_path,

385

pri_key_filepath=self.key_path

386

)

387

tls_context = io.ClientTlsContext(tls_context_options)

388

389

discovery_client = greengrass_discovery.DiscoveryClient(

390

bootstrap=client_bootstrap,

391

socket_options=socket_options,

392

tls_context=tls_context,

393

region=self.region

394

)

395

396

# Perform discovery

397

discover_future = discovery_client.discover(self.thing_name)

398

return discover_future.result(timeout=30)

399

400

except Exception as e:

401

print(f"Discovery failed: {e}")

402

return None

403

404

def _try_connect(self, core_info, timeout=10):

405

"""Try to connect to a specific core."""

406

try:

407

print(f"Trying to connect to {core_info['host']}:{core_info['port']}")

408

409

connection = mqtt_connection_builder.mtls_from_path(

410

endpoint=core_info['host'],

411

port=core_info['port'],

412

cert_filepath=self.cert_path,

413

pri_key_filepath=self.key_path,

414

ca_filepath=core_info['ca_file'],

415

client_id=self.thing_name,

416

clean_session=False,

417

keep_alive_secs=30

418

)

419

420

# Try to connect

421

connect_future = connection.connect()

422

connect_future.result(timeout=timeout)

423

424

self.current_connection = connection

425

print(f"Connected to Greengrass core: {core_info['core_arn']}")

426

return True

427

428

except Exception as e:

429

print(f"Connection failed to {core_info['host']}:{core_info['port']}: {e}")

430

return False

431

432

def reconnect(self):

433

"""Reconnect to Greengrass core with failover."""

434

if self.current_connection:

435

try:

436

self.current_connection.disconnect().result()

437

except:

438

pass

439

440

# Try current core first, then others

441

for core_info in self.discovered_cores:

442

if self._try_connect(core_info):

443

return True

444

445

# If all cores fail, try discovery again

446

print("All known cores failed, attempting rediscovery...")

447

return self.discover_and_connect()

448

449

def disconnect(self):

450

"""Disconnect from current core."""

451

if self.current_connection:

452

try:

453

disconnect_future = self.current_connection.disconnect()

454

disconnect_future.result()

455

print("Disconnected from Greengrass core")

456

except Exception as e:

457

print(f"Error during disconnect: {e}")

458

finally:

459

self.current_connection = None

460

461

# Usage

462

connector = GreengrassConnector(

463

thing_name="MyGreengrassDevice",

464

cert_path="/path/to/device-certificate.pem.crt",

465

key_path="/path/to/device-private.pem.key",

466

region="us-east-1"

467

)

468

469

if connector.discover_and_connect():

470

print("Successfully connected to Greengrass!")

471

472

# Your application logic here

473

try:

474

# Simulate work

475

time.sleep(60)

476

except KeyboardInterrupt:

477

pass

478

finally:

479

connector.disconnect()

480

else:

481

print("Failed to connect to Greengrass")

482

```

483

484

### Discovery Configuration

485

486

To use Greengrass discovery, ensure your device certificate has the necessary permissions:

487

488

1. **IoT Policy**: Attach a policy that allows discovery:

489

490

```json

491

{

492

"Version": "2012-10-17",

493

"Statement": [

494

{

495

"Effect": "Allow",

496

"Action": [

497

"greengrass:Discover"

498

],

499

"Resource": "*"

500

}

501

]

502

}

503

```

504

505

2. **Thing Association**: The device thing must be associated with a Greengrass group.

506

507

3. **Core Configuration**: The Greengrass core must be properly configured and running with connectivity information published.