위의 실습을 이어서 진행할 것이다.

https://realyun99.tistory.com/192


AWS Cloud에서 component를 배포하려면 먼저 recipe 파일을 확장해 S3의 component artifact를 참조한 다음 component artifact를 S3로 업로드 해야한다.

배포가 구성되면 디바이스가 S3에서 아티팩트를 다운로드 한다.

 

버킷을 만들고 다음 명령을 사용해 버킷 이름을 검색하는 명령어를 입력한다.

EPOCH_TIME=$(date +"%s") && S3_BUCKET=ggcv2-workshop-$HOSTNAME-$EPOCH_TIME && aws s3 mb s3://$S3_BUCKET

아래 코드 중 버킷이름을 위에서 검색했던 이름으로 변경하고 json 파일을 업데이트 해준다.

{
   "RecipeFormatVersion": "2020-01-25",
   "ComponentName": "com.example.HelloWorld",
   "ComponentVersion": "1.0.0",
   "ComponentDescription": "My first AWS IoT Greengrass component.",
   "ComponentPublisher": "Amazon",
   "ComponentConfiguration": {
      "DefaultConfiguration": {
         "Message": "world"
      }
   },
"Manifests": [
      {
         "Platform": {
            "os": "linux"
         },
         "Lifecycle": {
            "Run": "python3 -u {artifacts:path}/hello_world.py '{configuration:/Message}'\n"
         },
         "Artifacts": [
            {
               "URI": "s3://[YOUR BUCKET NAME]/artifacts/com.example.HelloWorld/1.0.0/hello_world.py"
            }
         ]
      }
   ]
}

component artifact를 업로드 해준다.

aws s3 cp --recursive /home/ubuntu/environment/GreengrassCore/ s3://$S3_BUCKET/

 

IoT Greengrass의 Component에서 Component 정의를 생성하는 과정이다.

cd /home/ubuntu/environment/GreengrassCore/recipes && aws greengrassv2 create-component-version  --inline-recipe fileb://com.example.HelloWorld-1.0.0.json --region $AWS_DEFAULT_REGION

# component 목록 확인
aws greengrassv2 list-components --region $AWS_DEFAULT_REGION

 

Pub/Sub IPC

Greengrass V2는 프로세스 간 통신을 위한 IPC SDK를 제공한다.

(custom component의 각 프로세스 간 Pub/Sub 통신이 가능하다.)

  • 센서 데이터를 읽고 토픽에 계속 pub하는 component, 해당 토픽 로그를 sub하고 메시지를 수신하는 component 및 IPC를 사용하는 custom component 를 만드는 과정

 

먼저 Publisher를 만들어보자.

데이터를 토픽에 pub하기 위해 더미 센서를 생성해야한다.

mkdir -p ~/environment/GreengrassCore/artifacts/com.example.Publisher/1.0.0 && cd ~/environment/GreengrassCore/artifacts/com.example.Publisher/1.0.0
touch example_publisher.py dummy_sensor.py

 

생성된 빈 스크립트 파일을 열고 아래 언급된 파일 이름에 따라 붙여 넣는다.

# dummy_sensor.py
from random import gauss

class DummySensor(object):
    def __init__(self, mean=25, variance=1):
        self.mu = mean
        self.sigma = variance
        
    def read_value(self):
        return float("%.2f" % (gauss(1000, 20)))

if __name__ == '__main__':
    sensor = DummySensor()
    print(sensor.read_value())


# example_publisher.py
import time
import datetime
import json
import awsiot.greengrasscoreipc
from awsiot.greengrasscoreipc.model import (
    PublishToTopicRequest,
    PublishMessage,
    JsonMessage
)
from dummy_sensor import DummySensor


TIMEOUT = 10
publish_rate = 1.0

ipc_client = awsiot.greengrasscoreipc.connect()

sensor = DummySensor()

topic = "my/topic"


while True:
    message = {"timestamp": str(datetime.datetime.now()),
               "value": sensor.read_value()}
    message_json = json.dumps(message).encode('utf-8')

    request = PublishToTopicRequest()
    request.topic = topic
    publish_message = PublishMessage()
    publish_message.json_message = JsonMessage()
    publish_message.json_message.message = message
    request.publish_message = publish_message
    operation = ipc_client.new_publish_to_topic()
    operation.activate(request)
    future = operation.get_response()
    future.result(TIMEOUT)

    print("publish")
    time.sleep(1/publish_rate)

 

recipe 폴더와 빈파일 생성

touch ~/environment/GreengrassCore/recipes/com.example.Publisher-1.0.0.json

해당 빈파일에 아래 내용 붙여 넣기

{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.Publisher",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.Publisher:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Install": "pip3 install awsiotsdk numpy",
        "Run": "python3 -u {artifacts:path}/example_publisher.py"
      }
    }
  ]
}

 

다음 명령을 실행해 component를 배포하자.

sudo /greengrass/v2/bin/greengrass-cli deployment create \
  --recipeDir ~/environment/GreengrassCore/recipes \
  --artifactDir ~/environment/GreengrassCore/artifacts \
  --merge "com.example.Publisher=1.0.0"

 

이젠 Subscriber의 차례다. 위 과정과 비슷하니 명령어와 코드만 적어 두겠다...

더보기
# 아티팩트 폴더, 빈 스크립트 파일 생성
mkdir -p ~/environment/GreengrassCore/artifacts/com.example.Subscriber/1.0.0 && cd ~/environment/GreengrassCore/artifacts/com.example.Subscriber/1.0.0
touch example_subscriber.py

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
import time
import json
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import (
    SubscribeToTopicRequest,
    SubscriptionResponseMessage
)

TIMEOUT = 10

ipc_client = awsiot.greengrasscoreipc.connect()


class StreamHandler(client.SubscribeToTopicStreamHandler):
    def __init__(self):
        super().__init__()

    def on_stream_event(self, event: SubscriptionResponseMessage) -> None:
        message_string = event.json_message.message
        with open('/tmp/Greengrass_Subscriber.log', 'a') as f:
            print(message_string, file=f)

    def on_stream_error(self, error: Exception) -> bool:
        return True

    def on_stream_closed(self) -> None:
        pass


topic = "my/topic"

request = SubscribeToTopicRequest()
request.topic = topic
handler = StreamHandler()
operation = ipc_client.new_subscribe_to_topic(handler)
future = operation.activate(request)
while True:
    time.sleep(1)

operation.close()

# 레시피 폴더와 빈파일 생성
touch ~/environment/GreengrassCore/recipes/com.example.Subscriber-1.0.0.json 

{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.Subscriber",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.Subscriber:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Install": "pip3 install awsiotsdk",
        "Run": "python3 -u {artifacts:path}/example_subscriber.py"
      }
    }
  ]
}

# 구성요소 배포
sudo /greengrass/v2/bin/greengrass-cli deployment create \
  --recipeDir ~/environment/GreengrassCore/recipes \
  --artifactDir ~/environment/GreengrassCore/artifacts \
  --merge "com.example.Subscriber=1.0.0"

받은 메시지가 계속 표시되면 성공한 것!

tail -f /tmp/Greengrass_Subscriber.log

 

Local MQTT Broker

여기까지는 Greengrass 디바이스가 데이터 공급자 역할을 할 수 있도록 허용하는 로컬 Pub/Sub 개념이였다.

그러나 데이터 공급자가 Greengrass 장치 외부에 있는 경우 MQTT 형식으로 게시 대상을 도입할 수 있다.

(Greengrass 장치를 로컬 MQTT 게이트웨이로 바꾸는 브릿지)

MQTT 브로커 구성 요소 배포를 진행하면 된다..

(배포 → 개정)

위의 구성요소 구성을 클릭한 뒤 아래의 코드를 넣어주면 된다.

# Auth
{
  "deviceGroups": {
    "formatVersion": "2021-03-05",
    "definitions": {
      "MyDeviceGroup": {
        "selectionRule": "thingName: MyClientDevice* OR thingName: MyOtherClientDevice*",
        "policyName": "MyClientDevicePolicy"
      }
    },
    "policies": {
      "MyClientDevicePolicy": {
        "AllowAll": {
          "statementDescription": "Allow client devices.",
          "operations": [
            "mqtt:connect",
            "mqtt:publish",
            "mqtt:subscribe"
          ],
          "resources": [
            "*"
          ]
        }
      }
    }
  }
}

# Bridge
{
   "mqttTopicMapping": {
     "HelloWorldIotCoreMapping": {
       "topic": "clients/+/hello/world",
       "source": "LocalMqtt",
       "target": "IotCore"
     }
   }
 }

이 실습에선 Mosquitto 클라이언트를 사용해 장치를 시뮬레이션 할 예정이다.

인증 구성 요소는 AWS IoT Core에서 AWS IoT 사물로 등록되고 사물과 연결된 동일한 인증서를 제공하는 디바이스를 지원한다.

 

Auth component 구성을 보면 이름이 MyClientDevice 로 시작하는 장치를 허용하고 있다.

cloud9 에 아래의 내용을 입력하자.

cd ~/environment
mkdir -p devices
cd devices
THING_NAME=MyClientDevice1
aws iot create-thing --thing-name $THING_NAME
CERTIFICATE_ARN=$(aws iot create-keys-and-certificate --private-key-out $THING_NAME.key --certificate-pem-out $THING_NAME.crt --query "certificateArn" --out text --set-as-active)
aws iot attach-thing-principal --thing-name $THING_NAME --principal $CERTIFICATE_ARN

cd ~/environment
mkdir -p devices
cd devices
THING_NAME=MyOtherClientDevice1
aws iot create-thing --thing-name $THING_NAME
CERTIFICATE_ARN=$(aws iot create-keys-and-certificate --private-key-out $THING_NAME.key --certificate-pem-out $THING_NAME.crt --query "certificateArn" --out text --set-as-active)
aws iot attach-thing-principal --thing-name $THING_NAME --principal $CERTIFICATE_ARN

 

MQTT를 통한 기기 통신 테스트를 해보면,

동일한 터미널에서 Mosquitto 클라이언트를 설치한다.

sudo apt install mosquitto-clients

 

다음으로 로컬 브로커 서버 인증서엥 서명하는 CA 인증서를 검색

(클라이언트가 브로커 엔드포인트를 확인하는데 사용됨)

cd ~/environment/devices
sudo cp /greengrass/v2/work/aws.greengrass.clientdevices.Auth/ca.pem .
sudo chmod 444 ca.pem

 

토픽 Subscribe를 해보자.

cd ~/environment/devices
mosquitto_sub -h localhost -p 8883 -q 0 -t clients/+/hello/world --cafile ca.pem --cert MyOtherClientDevice1.crt --key MyOtherClientDevice1.key -i MyOtherClientDevice1

 

메시지 publish (새 터미널 열고)

cd ~/environment/devices
mosquitto_pub -h localhost -p 8883 -q 0 -t clients/test/hello/world --cafile ca.pem --cert MyClientDevice1.crt --key MyClientDevice1.key -m "{\"message\": \""$2" @ "$(date +"%m-%d-%Y-%H-%M-%s")"\"}" -i MyClientDevice1

mosquitto_sub 명령을 실행하는 터미널에 메시지가 표시되어야 한다.

 

'Cloud > AWS' 카테고리의 다른 글

[AWS] Amazon OpenSearch Service 사용해보기  (0) 2023.08.23
[AWS] AWS IoT SiteWise 실습  (0) 2023.01.27
[AWS] AWS IoT Greengrass V2 실습  (0) 2023.01.26
[AWS] Firebase를 AWS Amplify로  (0) 2023.01.04
[AWS] re:Invent 2022 정리  (0) 2022.12.19

+ Recent posts