Skip to content

Commit 9e6f671

Browse files
committed
add Greengrass V2 IPC samples using new IPC-Client V2
1 parent d3115fd commit 9e6f671

File tree

12 files changed

+593
-54
lines changed

12 files changed

+593
-54
lines changed

Diff for: samples/greengrass_v2/README.md

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Greengrass V2 samples using AWS IoT Device SDK v2 for Python
2+
3+
You can find the full API documentation for the Greengrass V2 IPC interface using the Python SDK here: https://aws.github.io/aws-iot-device-sdk-python-v2/awsiot/greengrasscoreipc.html
4+
5+
## Sample: Low-Level IPC
6+
7+
Folder: `low_level_ipc/`
8+
9+
Once installed and running, this sample publishes messages to AWS IoT Core. It uses the low-level Greengrass v2 [Inter-Process-Communication API](https://docs.aws.amazon.com/greengrass/v2/developerguide/interprocess-communication.html).
10+
11+
See the other samples for higher-level APIs to reduce the amount of code you have to write and maintain.
12+
13+
## Sample: Publish/Subscribe to the cloud with AWS IoT Core
14+
15+
Folder: `pubsub_cloud`
16+
17+
Once installed and running, this sample subscribes to the `hello/world` topic. You can use the [MQTT Test Client](https://console.aws.amazon.com/iot/home#/test) to publish a message to this topic, while also subscribing to `hello/world/response` in the MQTT Test Client. The Greengrass device will receive the message and reply back on the response topic.
18+
19+
## Sample: Public/Subscribe on the local device between Greengrass components
20+
21+
Folder: `pubsub_local`
22+
23+
Once installed and running, this sample subscribes to the `hello/world` topic. You can use a second component to publish a message and receive a reply message on the `hello/world/response` topic. These messages are **not** sent to AWS IoT Core (the cloud). This pub/sub mechanism is only connecting different components running on the same Greengrass device. You can use the Greegrass CLI to publish or subscribe to these local topics:
24+
25+
* `greengrass-cli pubsub sub --topic hello/world/response`
26+
* `greengrass-cli pubsub pub --topic hello/world --message Hi!`
27+
28+
## Sample: Shadow Management
29+
30+
Folder: `shadows`
31+
32+
Once installed and running, this sample will retrieve a named shadow `special_shadow` when the component first starts executing, and then periodically update the shadow document with a new reported state every few seconds.
33+
34+
This component depends on the [AWS-provided ShadowManager component](https://docs.aws.amazon.com/greengrass/v2/developerguide/shadow-manager-component.html#shadow-manager-component-configuration). You [need to configure](https://docs.aws.amazon.com/greengrass/v2/developerguide/shadow-manager-component.html#shadow-manager-component-configuration) it to synchronize named shadows from the local device to the cloud:
35+
36+
```yaml
37+
strategy:
38+
type: realTime
39+
synchronize:
40+
coreThing:
41+
namedShadows:
42+
- special_shadow
43+
direction: betweenDeviceAndCloud
44+
```
45+
46+
## Sample: Deployment Configuration
47+
48+
Folder: `deployment_configuration`
49+
50+
Once installed and running, this sample will retrieve the component's deployment configuration and start a web server based on the provided parameters. Re-deploying with different parameters will update the component and upon restart of the Python process, it will start the web server based on these new parameters.
51+
52+
## Deployment Helpers
53+
54+
Deploy component locally using Greengrass CLI:
55+
56+
```bash
57+
func gg_deploy() {
58+
COMPONENT_NAME=$(sed -nr 's/ComponentName: ([a-zA-Z.-_]+)/\1/p' recipe.yaml)
59+
COMPONENT_VERSION=$(sed -nr 's/ComponentVersion: (.+)/\1/p' recipe.yaml | tr -d '"' | tr -d "'")
60+
61+
mkdir -p build/artifacts/$COMPONENT_NAME/$COMPONENT_VERSION/
62+
command cp code.py build/artifacts/$COMPONENT_NAME/$COMPONENT_VERSION/
63+
64+
mkdir -p build/recipes/
65+
command cp recipe.yaml build/recipes/$COMPONENT_NAME.yaml
66+
67+
RECIPES=$PWD/build/recipes
68+
ARTIFACTS=$PWD/build/artifacts
69+
sudo /greengrass/v2/bin/greengrass-cli deployment create \
70+
--recipeDir=$RECIPES \
71+
--artifactDir=$ARTIFACTS \
72+
--merge=$COMPONENT_NAME=$COMPONENT_VERSION
73+
}
74+
75+
func gg_remove() {
76+
COMPONENT_NAME=$(sed -nr 's/ComponentName: ([a-zA-Z.-_]+)/\1/p' recipe.yaml)
77+
sudo /greengrass/v2/bin/greengrass-cli deployment create \
78+
--recipeDir=$RECIPES \
79+
--artifactDir=$ARTIFACTS \
80+
--remove=$COMPONENT_NAME
81+
}
82+
```
+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
# SPDX-License-Identifier: Apache-2.0.
5+
6+
import time
7+
import os
8+
import http.server
9+
import socketserver
10+
11+
from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
12+
13+
client = GreengrassCoreIPCClientV2()
14+
thing_name = os.environ["AWS_IOT_THING_NAME"]
15+
16+
17+
def main():
18+
# https://docs.aws.amazon.com/greengrass/v2/developerguide/ipc-component-configuration.html
19+
config = client.get_configuration().value
20+
21+
print("This component was deployed with the following configuration:", config)
22+
23+
# example use case that takes component configuration as arguments for a webserver
24+
host = config["Webserver"]["Host"]
25+
port = config["Webserver"]["Port"]
26+
directory = config["Webserver"]["Directory"]
27+
28+
os.chdir(directory)
29+
30+
Handler = http.server.SimpleHTTPRequestHandler
31+
32+
with socketserver.TCPServer((host, port), Handler) as httpd:
33+
print(f"serving at {host}:{port} ...")
34+
httpd.serve_forever()
35+
36+
37+
if __name__ == "__main__":
38+
# Once we enter here, we know:
39+
# * all dependencies are available (imports succeeded)
40+
# * IPC Client created
41+
# * AWS_IOT_THING_NAME environment variable is available
42+
# This should be sufficient to consider this component `running` and the deployment will be completed.
43+
# If any of these failed, the component will be `broken`, and the deployment might roll-back or report the error.
44+
# Once the component is `running`, we need to try as hard as possible to keep it alive and running.
45+
while True:
46+
try:
47+
main()
48+
except Exception as e:
49+
print("ERROR", e)
50+
time.sleep(5)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# recipe reference: https://docs.aws.amazon.com/greengrass/v2/developerguide/component-recipe-reference.html
2+
---
3+
RecipeFormatVersion: "2020-01-25"
4+
ComponentName: com.example.greengrass_ipc.python.deployment_configuration
5+
ComponentVersion: "1.0.0"
6+
ComponentDescription: Greengrass IPC SDK component example
7+
ComponentPublisher: Amazon
8+
ComponentConfiguration:
9+
DefaultConfiguration:
10+
Webserver:
11+
Host: "127.0.0.1"
12+
Port: 8080
13+
Directory: "/greengrass/v2/packages/"
14+
Manifests:
15+
- Platform:
16+
os: linux
17+
Lifecycle:
18+
Install:
19+
RequiresPrivilege: true
20+
Script: |
21+
apt-get update
22+
apt-get install --yes python3 python3-pip
23+
python3 -m pip install "awsiotsdk>=1.15.0"
24+
Run: |
25+
python3 -u {artifacts:path}/code.py

Diff for: samples/greengrass_v2/low_level_ipc/code.py

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
# SPDX-License-Identifier: Apache-2.0.
5+
6+
import json
7+
import time
8+
import os
9+
import random
10+
11+
import awsiot.greengrasscoreipc
12+
import awsiot.greengrasscoreipc.model as model
13+
14+
ipc_client = awsiot.greengrasscoreipc.connect()
15+
thing_name = os.environ["AWS_IOT_THING_NAME"]
16+
17+
18+
def send_telemetry():
19+
telemetry_data = {
20+
"timestamp": int(time.time()),
21+
"battery_state_of_charge": random.random() * 99.9,
22+
"location": {
23+
"longitude": 48.15743 + random.random() / 10.0,
24+
"latitude": 11.57549 + random.random() / 10.0,
25+
},
26+
}
27+
28+
op = ipc_client.new_publish_to_iot_core()
29+
op.activate(
30+
model.PublishToIoTCoreRequest(
31+
topic_name=f"my/iot/{thing_name}/telemetry",
32+
qos=model.QOS.AT_LEAST_ONCE,
33+
payload=json.dumps(telemetry_data).encode(),
34+
)
35+
)
36+
try:
37+
result = op.get_response().result(timeout=5.0)
38+
print("successfully published message:", result)
39+
except Exception as e:
40+
print("failed to publish message:", e)
41+
42+
43+
def main():
44+
while True:
45+
send_telemetry()
46+
time.sleep(5)
47+
48+
49+
if __name__ == "__main__":
50+
# Once we enter here, we know:
51+
# * all dependencies are available (imports succeeded)
52+
# * IPC Client created
53+
# * AWS_IOT_THING_NAME environment variable is available
54+
# This should be sufficient to consider this component `running` and the deployment will be completed.
55+
# If any of these failed, the component will be `broken`, and the deployment might roll-back or report the error.
56+
# Once the component is `running`, we need to try as hard as possible to keep it alive and running.
57+
while True:
58+
try:
59+
main()
60+
except Exception as e:
61+
print("ERROR", e)
62+
time.sleep(5)

Diff for: samples/greengrass_v2/low_level_ipc/recipe.yaml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# recipe reference: https://docs.aws.amazon.com/greengrass/v2/developerguide/component-recipe-reference.html
2+
---
3+
RecipeFormatVersion: "2020-01-25"
4+
ComponentName: com.example.greengrass_ipc.python.low_level_ipc
5+
ComponentVersion: "1.0.0"
6+
ComponentDescription: Greengrass IPC SDK component example
7+
ComponentPublisher: Amazon
8+
ComponentConfiguration:
9+
DefaultConfiguration:
10+
accessControl:
11+
# see https://docs.aws.amazon.com/greengrass/v2/developerguide/ipc-iot-core-mqtt.html
12+
"aws.greengrass.ipc.mqttproxy":
13+
"com.example.greengrass_ipc.python.low_level_ipc:mqttproxy:1":
14+
policyDescription: Allow access to publish/subscribe to all topics on AWS IoT Core.
15+
operations:
16+
- "aws.greengrass#PublishToIoTCore"
17+
- "aws.greengrass#SubscribeToIoTCore"
18+
resources:
19+
- "*" # CHANGE ME: scope down based on principle of least privilege
20+
Manifests:
21+
- Platform:
22+
os: linux
23+
Lifecycle:
24+
Install:
25+
RequiresPrivilege: true
26+
Script: |
27+
apt-get update
28+
apt-get install --yes python3 python3-pip
29+
python3 -m pip install "awsiotsdk>=1.15.0"
30+
Run: |
31+
python3 -u {artifacts:path}/code.py

Diff for: samples/greengrass_v2/pubsub_cloud/code.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
# SPDX-License-Identifier: Apache-2.0.
5+
6+
import time
7+
import os
8+
import json
9+
10+
from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
11+
from awsiot.greengrasscoreipc.model import QOS, IoTCoreMessage
12+
13+
client = GreengrassCoreIPCClientV2()
14+
thing_name = os.environ["AWS_IOT_THING_NAME"]
15+
16+
17+
def on_stream_event(message: IoTCoreMessage):
18+
print(f"Message received:", message)
19+
reply = {
20+
"pong": "sending back what was received",
21+
"topic": message.message.topic_name,
22+
"payload": message.message.payload.decode(),
23+
}
24+
25+
print("Sending pong message back:", reply)
26+
resp = client.publish_to_iot_core(
27+
topic_name="hello/world/response",
28+
qos=QOS.AT_LEAST_ONCE,
29+
payload=json.dumps(reply),
30+
)
31+
print(resp)
32+
33+
34+
def main():
35+
print(f"Running pubsub-cloud sample for thing: {thing_name}")
36+
topic_name = "hello/world"
37+
38+
print(f"Subscribing to AWS IoT Core topic {topic_name}")
39+
resp, op = client.subscribe_to_iot_core(
40+
topic_name=topic_name,
41+
qos=QOS.AT_LEAST_ONCE,
42+
on_stream_event=on_stream_event,
43+
)
44+
print(resp, op)
45+
46+
while True:
47+
time.sleep(999) # wait for incoming messages
48+
49+
50+
if __name__ == "__main__":
51+
# Once we enter here, we know:
52+
# * all dependencies are available (imports succeeded)
53+
# * IPC Client created
54+
# * AWS_IOT_THING_NAME environment variable is available
55+
# This should be sufficient to consider this component `running` and the deployment will be completed.
56+
# If any of these failed, the component will be `broken`, and the deployment might roll-back or report the error.
57+
# Once the component is `running`, we need to try as hard as possible to keep it alive and running.
58+
while True:
59+
try:
60+
main()
61+
except Exception as e:
62+
print("ERROR", e)
63+
time.sleep(5)

Diff for: samples/greengrass_v2/pubsub_cloud/recipe.yaml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# recipe reference: https://docs.aws.amazon.com/greengrass/v2/developerguide/component-recipe-reference.html
2+
---
3+
RecipeFormatVersion: "2020-01-25"
4+
ComponentName: com.example.greengrass_ipc.python.pubsub_cloud
5+
ComponentVersion: "1.0.0"
6+
ComponentDescription: Greengrass IPC SDK component example
7+
ComponentPublisher: Amazon
8+
ComponentConfiguration:
9+
DefaultConfiguration:
10+
accessControl:
11+
# see https://docs.aws.amazon.com/greengrass/v2/developerguide/ipc-iot-core-mqtt.html
12+
"aws.greengrass.ipc.mqttproxy":
13+
"com.example.greengrass_ipc.python.pubsub_cloud:mqttproxy:1":
14+
policyDescription: Allow access to publish/subscribe to all topics on AWS IoT Core.
15+
operations:
16+
- "aws.greengrass#PublishToIoTCore"
17+
- "aws.greengrass#SubscribeToIoTCore"
18+
resources:
19+
- "*" # CHANGE ME: scope down based on principle of least privilege
20+
Manifests:
21+
- Platform:
22+
os: linux
23+
Lifecycle:
24+
Install:
25+
RequiresPrivilege: true
26+
Script: |
27+
apt-get update
28+
apt-get install --yes python3 python3-pip
29+
python3 -m pip install "awsiotsdk>=1.15.0"
30+
Run: |
31+
python3 -u {artifacts:path}/code.py

0 commit comments

Comments
 (0)