AWS IoT Greengrass 2.0でエッジからAWS IoT Coreにメッセージをパブリッシュしてみた。


前回の続きです。
Greengrass側で動作するPythonプログラムからAWS IoT Coreへメッセージをパブリッシュできました。

公式ドキュメントがまだ整ってないのでちょっと大変でした。
https://docs.aws.amazon.com/greengrass/v2/developerguide/interprocess-communication.html#ipc-iot-core-mqtt

環境

ハード:Raspberry Pi 4
OS:Raspberry Pi OS(32bit)

ディレクトリ構成

RaspberryPi
$ tree 
.
├── artifacts
│   └── com.example.HelloWorld
│       └── 1.0.0
│           ├── hello_world.py
│           └── ipc_utils.py
└── recipes
    └── com.example.HelloWorld-1.0.0.yaml

ソース

  • ipc_utils.py

これは公式ドキュメントにも記載があります。

ipc_utils.py
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

import os

from awscrt.io import (
    ClientBootstrap,
    DefaultHostResolver,
    EventLoopGroup,
    SocketDomain,
    SocketOptions,
)
from awsiot.eventstreamrpc import Connection, LifecycleHandler, MessageAmendment

TIMEOUT = 10


class IPCUtils:
    def connect(self):
        elg = EventLoopGroup()
        resolver = DefaultHostResolver(elg)
        bootstrap = ClientBootstrap(elg, resolver)
        socket_options = SocketOptions()
        socket_options.domain = SocketDomain.Local
        amender = MessageAmendment.create_static_authtoken_amender(os.getenv("SVCUID"))
        hostname = os.getenv("AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT")
        connection = Connection(
            host_name=hostname,
            port=8033,
            bootstrap=bootstrap,
            socket_options=socket_options,
            connect_message_amender=amender,
        )
        self.lifecycle_handler = LifecycleHandler()
        connect_future = connection.connect(self.lifecycle_handler)
        connect_future.result(TIMEOUT)
        return connection
  • hello_world.py

Javaのサンプルを参考に、頑張ってみました。

hello_world.py
import awsiot.greengrasscoreipc.client as client
import awsiot.greengrasscoreipc.model as model
from ipc_utils import IPCUtils
import json

print("Start Lambda !!!")

ipc_utils = IPCUtils()
connection = ipc_utils.connect()
ipc_client = client.GreengrassCoreIPCClient(connection)

message = {"hello": "world"}
message = json.dumps(message).encode('utf-8')

request = ipc_client.new_publish_to_iot_core()

publishMessage = model.PublishToIoTCoreRequest(topic_name='test/topic', qos='1', payload=message)

future = request.activate(publishMessage)
result = future.result(timeout=10.0)

print("Finish Lambda !!!")
  • com.example.HelloWorld-1.0.0.yaml

レシピの書き方が大苦戦。。

accessControlのところはaws.greengrass.ipc.mqttproxy
operationsがaws.greengrass#PublishToIoTCore
resourcesがトピック名です。
Greengrass 1.0のころのサブスクリプションのイメージですね。

com.example.HelloWorld-1.0.0.yaml
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.HelloWorld
ComponentVersion: '1.0.0'
ComponentDescription: A component that publishes messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        "com.example.HelloWorld:pubsub:1":
          policyDescription: Allows access to publish to test/topic.
          operations:
            - "aws.greengrass#PublishToIoTCore"
          resources:
            - "test/topic"
Manifests:
  - Lifecycle:
      Install:
        Timeout: 1000
        Script: pip3 install awsiotsdk
      Run: |
        python3 {artifacts:path}/hello_world.py

デプロイ

Greengrass 2.0の特徴で、「Lambdaにデプロイせずにローカルでデプロイできる」機能があります。

RaspberryPi
sudo /greengrass/v2/bin/greengrass-cli \
    --ggcRootPath=/greengrass/v2 \
    deployment create \
    --recipeDir recipes \
    --artifactDir artifacts \
    --merge "com.example.HelloWorld=1.0.0"

おめでとうございます!!!