튜토리얼: MQTT를 통해 로컬 IoT 디바이스와 상호 작용 - AWS IoT Greengrass

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

튜토리얼: MQTT를 통해 로컬 IoT 디바이스와 상호 작용

이 자습서를 완료하여 MQTT를 통해 코어 장치에 연결되는 로컬 IoT 장치 (클라이언트 장치라고 함) 와 상호 작용하도록 코어 장치를 구성할 수 있습니다. 이 자습서에서는 클라우드 검색을 사용하여 코어 장치를 클라이언트 장치로 연결하도록 AWS IoT 사물을 구성합니다. 클라우드 검색을 구성하면 클라이언트 장치가 AWS IoT Greengrass 클라우드 서비스에 요청을 보내 핵심 장치를 검색할 수 있습니다. 응답의 응답에는 검색하도록 클라이언트 장치를 구성한 핵심 장치에 대한 연결 정보 및 인증서가 AWS IoT Greengrass 포함됩니다. 그러면 클라이언트 장치는 이 정보를 사용하여 MQTT를 통해 통신할 수 있는 사용 가능한 코어 장치에 연결할 수 있습니다.

이 자습서에서는 다음 작업을 수행합니다.

  1. 필요한 경우 코어 디바이스의 권한을 검토하고 업데이트하십시오.

  2. 클라이언트 디바이스를 코어 디바이스에 연결하여 클라우드 검색을 사용하여 코어 디바이스를 검색할 수 있도록 합니다.

  3. Greengrass 구성 요소를 코어 장치에 배포하여 클라이언트 장치 지원을 활성화합니다.

  4. 클라이언트 디바이스를 코어 디바이스에 연결하고 AWS IoT Core 클라우드 서비스와의 통신을 테스트합니다.

  5. 클라이언트 장치와 통신하는 사용자 지정 Greengrass 구성 요소를 개발하십시오.

  6. 클라이언트 디바이스의 디바이스 AWS IoT 섀도우와 상호 작용하는 사용자 지정 구성 요소를 개발하십시오.

이 자습서에서는 단일 코어 기기와 단일 클라이언트 기기를 사용합니다. 자습서를 따라 여러 클라이언트 장치를 연결하고 테스트할 수도 있습니다.

이 자습서에는 30~60분이 소요될 것으로 예상됩니다.

사전 조건

이 튜토리얼을 완료하려면 다음이 필요합니다.

  • AWS 계정. 계정이 없는 경우 설정 AWS 계정 섹션을 참조하십시오.

  • 관리자 권한이 있는 AWS Identity and Access Management (IAM) 사용자.

  • 그린그래스 코어 디바이스. 코어 디바이스 설정 방법에 대한 자세한 내용은 을 참조하십시오AWS IoT Greengrass 코어 디바이스 설정.

    • 코어 디바이스는 그린그래스 핵 v2.6.0 이상을 실행해야 합니다. 이 버전에는 로컬 게시/구독 커뮤니케이션의 와일드카드 지원 및 클라이언트 디바이스 섀도 지원이 포함됩니다.

      참고

      클라이언트 장치 지원을 위해서는 그린그래스 핵 v2.2.0 이상이 필요합니다. 하지만 이 자습서에서는 로컬 퍼블리시/서브스크립션의 MQTT 와일드카드 지원 및 클라이언트 디바이스 섀도 지원과 같은 새로운 기능을 살펴봅니다. 이러한 기능을 사용하려면 그린그래스 핵 v2.6.0 이상이 필요합니다.

    • 코어 디바이스는 연결할 클라이언트 디바이스와 동일한 네트워크에 있어야 합니다.

    • (선택 사항) 사용자 지정 Greengrass 구성 요소를 개발하는 모듈을 완료하려면 코어 디바이스에서 Greengrass CLI를 실행해야 합니다. 자세한 설명은 그린그래스 설치 CLI 섹션을 참조하세요.

  • 이 AWS IoT 튜토리얼에서는 클라이언트 디바이스로 연결하는 방법에 대해 설명합니다. 자세한 내용은 AWS IoT Core개발자 안내서에서 AWS IoT 리소스 만들기를 참조하십시오.

    • 클라이언트 장치의 AWS IoT 정책에서 greengrass:Discover 권한을 허용해야 합니다. 자세한 설명은 클라이언트 디바이스에 대한 최소 AWS IoT 정책 섹션을 참조하세요.

    • 클라이언트 장치는 코어 장치와 동일한 네트워크에 있어야 합니다.

    • 클라이언트 기기는 Python 3을 실행해야 합니다.

    • 클라이언트 디바이스는 Git을 실행해야 합니다.

1단계: 코어 디바이스 AWS IoT 정책 검토 및 업데이트

클라이언트 장치를 지원하려면 코어 장치 AWS IoT 정책에서 다음 권한을 허용해야 합니다.

  • greengrass:PutCertificateAuthorities

  • greengrass:VerifyClientDeviceIdentity

  • greengrass:VerifyClientDeviceIoTCertificateAssociation

  • greengrass:GetConnectivityInfo

  • greengrass:UpdateConnectivityInfo— (선택 사항) 코어 디바이스의 네트워크 연결 정보를 AWS IoT Greengrass 클라우드 서비스에 보고하는 IP Detector 구성 요소를 사용하려면 이 권한이 필요합니다.

핵심 장치에 대한 이러한 권한 및 AWS IoT 정책에 대한 자세한 내용은 데이터 영역 작업에 대한 AWS IoT 정책 및 을 참조하십시오클라이언트 AWS IoT 장치를 지원하기 위한 최소 정책.

이 섹션에서는 코어 장치에 대한 AWS IoT 정책을 검토하고 누락된 필수 권한을 추가합니다. AWS IoT Greengrass코어 소프트웨어 설치 프로그램을 사용하여 리소스를 프로비저닝한 경우 코어 장치에는 모든 AWS IoT Greengrass 작업에 대한 액세스를 허용하는 AWS IoT 정책이 있습니다 (greengrass:*). 이 경우 섀도우 관리자 구성 요소가 장치 섀도우와 AWS IoT Core 동기화되도록 구성하려는 경우에만 AWS IoT 정책을 업데이트해야 합니다. 그렇지 않으면 이 섹션을 건너뛰어도 됩니다.

핵심 장치 정책을 검토 및 업데이트하려면 AWS IoT
  1. AWS IoT Greengrass콘솔 탐색 메뉴에서 코어 기기를 선택합니다.

  2. 코어 디바이스 페이지에서 업데이트할 코어 디바이스를 선택합니다.

  3. 코어 디바이스 세부 정보 페이지에서 코어 디바이스의 사물로 연결되는 링크를 선택합니다. 이 링크를 클릭하면 AWS IoT 콘솔에서 사물 세부 정보 페이지가 열립니다.

  4. 사물 세부 정보 페이지에서 인증서를 선택합니다.

  5. 인증서 탭에서 사물의 활성 인증서를 선택합니다.

  6. 인증서 세부 정보 페이지에서 정책을 선택합니다.

  7. 정책 탭에서 검토 및 업데이트할 AWS IoT 정책을 선택합니다. 코어 디바이스의 활성 인증서에 연결된 모든 정책에 필요한 권한을 추가할 수 있습니다.

    참고

    AWS IoT Greengrass코어 소프트웨어 설치 프로그램을 사용하여 리소스를 프로비저닝한 경우 두 가지 AWS IoT 정책이 있습니다. 이름이 지정된 정책을 선택하는 것이 좋습니다 (있는 GreengrassV2IoTThingPolicy경우). 빠른 설치 프로그램으로 만든 코어 디바이스는 기본적으로 이 정책 이름을 사용합니다. 이 정책에 권한을 추가하면 이 정책을 사용하는 다른 핵심 장치에도 이러한 권한이 부여됩니다.

  8. 정책 개요에서 활성 버전 편집을 선택합니다.

  9. 정책에서 필요한 권한을 검토하고 누락된 필수 권한을 추가하십시오.

  10. 새 정책 버전을 활성 버전으로 설정하려면 정책 버전 상태에서 편집한 버전을 이 정책의 활성 버전으로 설정을 선택합니다.

  11. 새 버전으로 저장을 선택합니다.

2단계: 클라이언트 장치 지원 활성화

클라이언트 장치가 클라우드 검색을 사용하여 코어 장치에 연결하려면 장치를 연결해야 합니다. 클라이언트 장치를 코어 장치에 연결하면 해당 클라이언트 장치가 연결에 사용할 핵심 장치의 IP 주소 및 인증서를 검색할 수 있도록 합니다.

클라이언트 장치를 코어 장치에 안전하게 연결하고 Greengrass 구성 요소와 통신할 수 있도록 하려면 다음 Greengrass 구성 요소를 코어 장치에 배포합니다. AWS IoT Core

  • 클라이언트 장치 인증 (aws.greengrass.clientdevices.Auth)

    클라이언트 장치 인증 구성 요소를 배포하여 클라이언트 장치를 인증하고 클라이언트 장치 작업을 승인합니다. 이 구성 요소를 사용하면 AWS IoT 사물을 코어 장치에 연결할 수 있습니다.

    이 구성 요소를 사용하려면 몇 가지 구성이 필요합니다. 클라이언트 장치 그룹과 각 그룹이 수행할 권한이 있는 작업 (예: MQTT를 통한 연결 및 통신) 을 지정해야 합니다. 자세한 내용은 클라이언트 장치 인증 구성 요소 구성을 참조하십시오.

  • MQTT 3.1.1 브로커 (모켓) (aws.greengrass.clientdevices.mqtt.Moquette)

    Mocquette MQTT 브로커 구성 요소를 배포하여 경량 MQTT 브로커를 실행하십시오. Moquette MQTT 브로커는 MQTT 3.1.1과 호환되며 QoS 0, QoS 1, QoS 2, 보존 메시지, 라스트 윌 메시지 및 영구 구독에 대한 로컬 지원을 포함합니다.

    이 구성 요소를 사용하기 위해 구성하지 않아도 됩니다. 하지만 이 구성 요소가 MQTT 브로커를 작동하는 포트를 구성할 수 있습니다. 기본적으로 포트 8883을 사용합니다.

  • MQTT 브리지 (aws.greengrass.clientdevices.mqtt.Bridge)

    (선택 사항) MQTT 브리지 구성 요소를 배포하여 클라이언트 장치 (로컬 MQTT), 로컬 게시/구독 및 MQTT 간에 메시지를 릴레이합니다. AWS IoT Core 클라이언트 장치를 Greengrass 구성 요소의 클라이언트 장치와 AWS IoT Core 동기화하고 클라이언트 장치와 상호 작용하도록 이 구성 요소를 구성합니다.

    이 구성 요소를 사용하려면 구성이 필요합니다. 이 구성 요소가 메시지를 릴레이하는 주제 매핑을 지정해야 합니다. 자세한 내용은 MQTT 브리지 구성 요소 구성을 참조하십시오.

  • IP 감지기 (aws.greengrass.clientdevices.IPDetector)

    (선택 사항) 코어 디바이스의 MQTT 브로커 엔드포인트를 클라우드 서비스에 자동으로 보고하도록 IP 탐지기 구성 요소를 배포하십시오AWS IoT Greengrass. 라우터가 MQTT 브로커 포트를 코어 디바이스에 전달하는 것과 같이 복잡한 네트워크 설정이 있는 경우에는 이 구성 요소를 사용할 수 없습니다.

    이 구성 요소를 사용하도록 구성하지 않아도 됩니다.

이 섹션에서는 AWS IoT Greengrass 콘솔을 사용하여 클라이언트 장치를 연결하고 클라이언트 장치 구성 요소를 코어 장치에 배포합니다.

클라이언트 장치 지원을 활성화하려면
  1. 왼쪽 탐색 메뉴에서 코어 기기를 선택합니다.

  2. 코어 디바이스 페이지에서 클라이언트 디바이스 지원을 활성화하려는 코어 디바이스를 선택합니다.

  3. 코어 장치 세부 정보 페이지에서 클라이언트 장치 탭을 선택합니다.

  4. 클라이언트 디바이스 탭에서 클라우드 검색 구성을 선택합니다.

    코어 디바이스 검색 구성 페이지가 열립니다. 이 페이지에서 클라이언트 장치를 코어 장치에 연결하고 클라이언트 장치 구성 요소를 배포할 수 있습니다. 이 페이지에서는 1단계: 대상 코어 장치 선택에서 자동으로 코어 장치를 선택합니다.

    참고

    또한 이 페이지를 사용하여 사물 그룹에 대한 코어 장치 검색을 구성할 수 있습니다. 이 옵션을 선택하면 사물 그룹의 모든 핵심 장치에 클라이언트 장치 구성 요소를 배포할 수 있습니다. 하지만 이 옵션을 선택하면 나중에 배포를 생성한 후 클라이언트 디바이스를 각 코어 디바이스에 수동으로 연결해야 합니다. 이 자습서에서는 싱글 코어 디바이스를 구성합니다.

  5. 2단계: 클라이언트 장치 연결에서 클라이언트 장치의 AWS IoT 사물을 코어 장치에 연결합니다. 이렇게 하면 클라이언트 장치가 클라우드 검색을 사용하여 코어 장치의 연결 정보 및 인증서를 검색할 수 있습니다. 다음을 따릅니다.

    1. [클라이언트 장치 연결] 을 선택합니다.

    2. 클라이언트 장치를 코어 장치와 연결 모달에 연결할 사물의 AWS IoT 이름을 입력합니다.

    3. Add(추가)를 선택합니다.

    4. Associate(연결)를 선택합니다.

  6. 3단계: Greengrass 구성 요소 구성 및 배포에서 구성 요소를 배포하여 클라이언트 장치 지원을 활성화합니다. 대상 코어 장치에 이전 배포가 있는 경우 이 페이지는 해당 배포를 수정합니다. 그렇지 않으면 이 페이지에서 코어 장치에 대한 새 배포를 생성합니다. 클라이언트 장치 구성 요소를 구성하고 배포하려면 다음과 같이 하십시오.

    1. 이 튜토리얼을 완료하려면 코어 디바이스에서 Greengrass nucleus v2.6.0 이상을 실행해야 합니다. 코어 디바이스가 이전 버전을 실행하는 경우 다음을 수행하십시오.

      1. 상자를 선택하여 aws.greengrass.Nucleus구성 요소를 배포합니다.

      2. aws.greengrass.Nucleus구성 요소의 경우 구성 편집을 선택합니다.

      3. 구성 요소 버전의 경우 버전 2.6.0 이상을 선택합니다.

      4. 확인을 선택합니다.

      참고

      Greengrass nucleus를 이전 마이너 버전에서 업그레이드하고 코어 디바이스가 핵에 종속된 AWS-제공 구성 요소를 실행하는 경우 AWS -제공 구성 요소도 최신 버전으로 업데이트해야 합니다. 이 자습서의 뒷부분에서 배포를 검토할 때 이러한 구성 요소의 버전을 구성할 수 있습니다. 자세한 설명은 AWS IoT Greengrass코어 소프트웨어 (OTA) 업데이트 섹션을 참조하세요.

    2. aws.greengrass.clientdevices.Auth구성 요소의 경우 구성 편집을 선택합니다.

    3. 클라이언트 장치 인증 구성 요소의 구성 편집 모달에서 클라이언트 장치가 코어 장치의 MQTT 브로커를 게시하고 구독하도록 허용하는 권한 부여 정책을 구성합니다. 다음을 따릅니다.

      1. 구성에서 코드를 병합할 구성 블록에 클라이언트 장치 권한 부여 정책이 포함된 다음 구성을 입력합니다. 각 장치 그룹 권한 부여 정책은 일련의 작업과 클라이언트 장치가 해당 작업을 수행할 수 있는 리소스를 지정합니다.

        • 이 정책은 이름이 로 MyClientDevice 시작하는 클라이언트 장치가 모든 MQTT 주제에 연결하고 통신할 수 있도록 허용합니다. MyClientDevice*를 클라이언트 장치로 연결할 AWS IoT 사물의 이름으로 바꾸십시오. *와일드카드로 클라이언트 장치 이름과 일치하는 이름을 지정할 수도 있습니다. *와일드카드는 이름 끝에 있어야 합니다.

          연결할 두 번째 클라이언트 장치가 있는 경우, MyOtherClientDevice*를 해당 클라이언트 장치의 이름 또는 해당 클라이언트 장치의 이름과 일치하는 와일드카드 패턴으로 바꾸십시오. 그렇지 않으면 이름이 일치하는 MyOtherClientDevice* 클라이언트 장치가 연결 및 통신할 수 있도록 허용하는 선택 규칙의 이 섹션을 제거하거나 유지할 수 있습니다.

        • 이 정책은 OR 운영자를 사용하여 이름이 로 MyOtherClientDevice 시작하는 클라이언트 장치가 모든 MQTT 주제에 대해 연결 및 통신할 수 있도록 허용합니다. 선택 규칙에서 이 조항을 제거하거나 연결할 클라이언트 장치에 맞게 수정할 수 있습니다.

        • 이 정책을 통해 클라이언트 장치는 모든 MQTT 주제를 게시하고 구독할 수 있습니다. 최상의 보안 관행을 따르려면 mqtt:publishmqtt:subscribe 작업을 클라이언트 장치가 통신하는 데 사용하는 최소 주제 집합으로 제한하십시오.

        { "deviceGroups": { "formatVersion": "2021-03-05", "definitions": { "MyDeviceGroup": { "selectionRule": "thingName: MyClientDevice* OR thingName: MyOtherClientDevice*", "policyName": "MyClientDevicePolicy" } }, "policies": { "MyClientDevicePolicy": { "AllowConnect": { "statementDescription": "Allow client devices to connect.", "operations": [ "mqtt:connect" ], "resources": [ "*" ] }, "AllowPublish": { "statementDescription": "Allow client devices to publish to all topics.", "operations": [ "mqtt:publish" ], "resources": [ "*" ] }, "AllowSubscribe": { "statementDescription": "Allow client devices to subscribe to all topics.", "operations": [ "mqtt:subscribe" ], "resources": [ "*" ] } } } } }

        자세한 내용은 클라이언트 장치 인증 구성 요소 구성을 참조하십시오.

      2. 확인을 선택합니다.

    4. aws.greengrass.clientdevices.mqtt.Bridge구성 요소의 경우 구성 편집을 선택합니다.

    5. MQTT 브리지 구성 요소의 구성 편집 모달에서 클라이언트 장치의 MQTT 메시지를 릴레이하는 주제 매핑을 구성합니다. AWS IoT Core 다음을 따릅니다.

      1. 구성의 코드 병합을 위한 구성 블록에 다음 구성을 입력합니다. 이 구성은 clients/+/hello/world 주제 필터에 대한 MQTT 메시지를 클라이언트 장치에서 AWS IoT Core 클라우드 서비스로 릴레이하도록 지정합니다. 예를 들어, 이 주제 필터는 주제와 일치합니다. clients/MyClientDevice1/hello/world

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

        자세한 내용은 MQTT 브리지 구성 요소 구성을 참조하십시오.

      2. 확인을 선택합니다.

  7. 검토 및 배포를 선택하여 이 페이지에서 생성한 배포를 검토하십시오.

  8. 이 지역에서 Greengrass 서비스 역할을 이전에 설정하지 않은 경우 콘솔에서 서비스 역할을 설정하는 모드가 열립니다. 클라이언트 장치 인증 구성 요소는 이 서비스 역할을 사용하여 클라이언트 장치의 ID를 확인하고 IP 탐지기 구성 요소는 이 서비스 역할을 사용하여 핵심 장치 연결 정보를 관리합니다. 권한 부여를 선택합니다.

  9. 검토 페이지에서 [Deploy] 를 선택하여 코어 장치에 대한 배포를 시작합니다.

  10. 배포가 성공했는지 확인하려면 배포 상태를 확인하고 코어 장치의 로그를 확인하십시오. 코어 디바이스의 배포 상태를 확인하려면 배포 개요에서 타겟을 선택하면 됩니다. 자세한 내용은 다음 자료를 참조하세요.

3단계: 클라이언트 장치 연결

클라이언트 장치는 AWS IoT Device SDK 를 사용하여 코어 장치를 검색, 연결 및 통신할 수 있습니다. 클라이언트 디바이스는 AWS IoT 사물이어야 합니다. 자세한 내용은 AWS IoT Core개발자 안내서의 사물 객체 만들기를 참조하십시오.

이 섹션에서는 Python용 AWS IoT Device SDK v2를 설치하고 에서 Greengrass 검색 샘플 애플리케이션을 실행합니다. AWS IoT Device SDK

참고

다른 프로그래밍 언어로도 사용할 수 있습니다. AWS IoT Device SDK 이 자습서에서는 Python용 AWS IoT Device SDK v2를 사용하지만 사용 사례에 맞는 다른 SDK도 살펴볼 수 있습니다. 자세한 내용은 AWS IoT Core 개발자 안내서AWS IoT 디바이스 SDK 섹션을 참조하세요.

클라이언트 디바이스를 코어 디바이스에 연결하려면
  1. AWS IoT Device SDKv2용 Python을 AWS IoT 다운로드하여 클라이언트 장치로 연결할 사물에 설치합니다.

    클라이언트 기기에서 다음을 수행하십시오.

    1. AWS IoT Device SDKv2 for Python 저장소를 복제하여 다운로드하십시오.

      git clone https://github.com/aws/aws-iot-device-sdk-python-v2.git
    2. Python용 AWS IoT Device SDK v2를 설치합니다.

      python3 -m pip install --user ./aws-iot-device-sdk-python-v2
  2. Python용 AWS IoT Device SDK v2의 샘플 폴더로 변경합니다.

    cd aws-iot-device-sdk-python-v2/samples
  3. 샘플 Greengrass 검색 애플리케이션을 실행합니다. 이 애플리케이션에는 클라이언트 디바이스 사물 이름, 사용할 MQTT 주제 및 메시지, 연결을 인증하고 보호하는 인증서를 지정하는 인수가 필요합니다. 다음 예제에서는 주제에 Hello World 메시지를 보냅니다. clients/MyClientDevice1/hello/world

    참고

    이 항목은 메시지를 AWS IoT Core 이전으로 릴레이하도록 MQTT 브리지를 구성한 주제와 일치합니다.

    • MyClientDevice1을 클라이언트 디바이스의 사물 이름으로 바꾸십시오.

    • ~/certs/ AmazonRoot ca1.pem을 클라이언트 디바이스의 Amazon 루트 CA 인증서 경로로 바꾸십시오.

    • ~/certs/device.pem.crt를 클라이언트 디바이스의 디바이스 인증서 경로로 바꾸십시오.

    • ~/certs/private.pem.key를 클라이언트 장치의 개인 키 파일 경로로 바꾸십시오.

    • us-east-1을 클라이언트 디바이스 및 코어 디바이스가 운영되는 지역으로 바꾸십시오. AWS

    python3 basic_discovery.py \\ --thing_name MyClientDevice1 \\ --topic 'clients/MyClientDevice1/hello/world' \\ --message 'Hello World!' \\ --ca_file ~/certs/AmazonRootCA1.pem \\ --cert ~/certs/device.pem.crt \\ --key ~/certs/private.pem.key \\ --region us-east-1 \\ --verbosity Warn

    검색 샘플 애플리케이션은 메시지를 10번 전송하고 연결을 끊습니다. 또한 메시지를 게시하는 동일한 주제를 구독합니다. 애플리케이션에서 해당 주제에 대한 MQTT 메시지를 수신했다고 출력에 표시되면 클라이언트 기기는 코어 기기와 성공적으로 통신할 수 있습니다.

    Performing greengrass discovery... awsiot.greengrass_discovery.DiscoverResponse(gg_groups=[awsiot.greengrass_discovery.GGGroup(gg_group_id='greengrassV2-coreDevice-MyGreengrassCore', cores=[awsiot.greengrass_discovery.GGCore(thing_arn='arn:aws:iot:us-east-1:123456789012:thing/MyGreengrassCore', connectivity=[awsiot.greengrass_discovery.ConnectivityInfo(id='203.0.113.0', host_address='203.0.113.0', metadata='', port=8883)])], certificate_authorities=['-----BEGIN CERTIFICATE-----\ MIICiT...EXAMPLE=\ -----END CERTIFICATE-----\ '])]) Trying core arn:aws:iot:us-east-1:123456789012:thing/MyGreengrassCore at host 203.0.113.0 port 8883 Connected! Published topic clients/MyClientDevice1/hello/world: {"message": "Hello World!", "sequence": 0} Publish received on topic clients/MyClientDevice1/hello/world b'{"message": "Hello World!", "sequence": 0}' Published topic clients/MyClientDevice1/hello/world: {"message": "Hello World!", "sequence": 1} Publish received on topic clients/MyClientDevice1/hello/world b'{"message": "Hello World!", "sequence": 1}' ... Published topic clients/MyClientDevice1/hello/world: {"message": "Hello World!", "sequence": 9} Publish received on topic clients/MyClientDevice1/hello/world b'{"message": "Hello World!", "sequence": 9}'

    애플리케이션이 대신 오류를 출력하는 경우 Greengrass 검색 문제 해결을 참조하십시오.

    또한 코어 디바이스의 Greengrass 로그를 확인하여 클라이언트 디바이스가 성공적으로 연결하고 메시지를 전송하는지 확인할 수 있습니다. 자세한 설명은 모니터 AWS IoT Greengrass 로그 섹션을 참조하세요.

  4. MQTT 브리지가 클라이언트 장치의 메시지를 중계하는지 확인하십시오. AWS IoT Core AWS IoT Core콘솔의 MQTT 테스트 클라이언트를 사용하여 MQTT 주제 필터를 구독할 수 있습니다. 다음을 따릅니다.

    1. AWS IoT 콘솔로 이동합니다.

    2. 왼쪽 탐색 메뉴의 테스트에서 MQTT 테스트 클라이언트를 선택합니다.

    3. 주제 구독 탭의 주제 필터에 코어 기기의 클라이언트 장치 메시지를 clients/+/hello/world 구독하도록 입력합니다.

    4. 구독을 선택합니다.

    5. 클라이언트 장치에서 게시/구독 애플리케이션을 다시 실행합니다.

      MQTT 테스트 클라이언트는 이 주제 필터와 일치하는 주제에 대해 클라이언트 장치에서 보내는 메시지를 표시합니다.

4단계: 클라이언트 기기와 통신하는 구성 요소 개발

클라이언트 장치와 통신하는 Greengrass 구성 요소를 개발할 수 있습니다. 구성 요소는 IPC (프로세스 간 통신)로컬 게시/구독 인터페이스를 사용하여 코어 장치에서 통신합니다. 클라이언트 장치와 상호 작용하려면 클라이언트 장치와 로컬 게시/구독 인터페이스 간에 메시지를 릴레이하도록 MQTT 브리지 구성 요소를 구성하십시오.

이 섹션에서는 클라이언트 장치의 메시지를 로컬 게시/구독 인터페이스로 릴레이하도록 MQTT 브리지 구성 요소를 업데이트합니다. 그런 다음 이러한 메시지를 구독하고 메시지를 수신하면 메시지를 인쇄하는 구성 요소를 개발합니다.

클라이언트 장치와 통신하는 구성 요소 개발
  1. 배포를 코어 장치로 수정하고 클라이언트 장치의 메시지를 로컬 게시/구독으로 릴레이하도록 MQTT 브리지 구성 요소를 구성합니다. 다음을 따릅니다.

    1. 왼쪽 탐색 메뉴에서 Core devices를 선택합니다.

    2. 코어 디바이스 페이지에서 이 튜토리얼에 사용 중인 코어 디바이스를 선택합니다.

    3. 코어 장치 세부 정보 페이지에서 클라이언트 장치 탭을 선택합니다.

    4. 클라이언트 디바이스 탭에서 클라우드 검색 구성을 선택합니다.

      코어 디바이스 검색 구성 페이지가 열립니다. 이 페이지에서 코어 장치에 배포할 클라이언트 장치 구성 요소를 변경하거나 구성할 수 있습니다.

    5. 3단계에서 aws.greengrass.clientdevices.mqtt.Bridge구성 요소에 대해 구성 편집을 선택합니다.

    6. MQTT 브리지 구성 요소의 구성 편집 모달에서 클라이언트 장치의 MQTT 메시지를 로컬 게시/구독 인터페이스로 릴레이하는 주제 매핑을 구성합니다. 다음을 따릅니다.

      1. 구성의 코드 병합 구성 블록에 다음 구성을 입력합니다. 이 구성은 주제 필터와 일치하는 주제에 대한 MQTT 메시지를 클라이언트 장치에서 AWS IoT Core 클라우드 서비스 및 로컬 Greengrass 게시/구독 브로커로 중계하도록 지정합니다. clients/+/hello/world

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

        자세한 내용은 MQTT 브리지 구성 요소 구성을 참조하십시오.

      2. 확인을 선택합니다.

    7. 검토 및 배포를 선택하여 이 페이지에서 생성한 배포를 검토하십시오.

    8. 검토 페이지에서 [Deploy] 를 선택하여 코어 장치에 대한 배포를 시작합니다.

    9. 배포가 성공했는지 확인하려면 배포 상태를 확인하고 코어 장치의 로그를 확인하십시오. 코어 디바이스의 배포 상태를 확인하려면 배포 개요에서 타겟을 선택하면 됩니다. 자세한 내용은 다음 자료를 참조하세요.

  2. 클라이언트 장치의 Hello World 메시지를 구독하는 Greengrass 구성 요소를 개발하고 배포합니다. 다음을 따릅니다.

    1. 코어 디바이스에 레시피와 아티팩트를 저장할 폴더를 만드세요.

      Linux or Unix
      mkdir recipes mkdir -p artifacts/com.example.clientdevices.MyHelloWorldSubscriber/1.0.0
      Windows Command Prompt (CMD)
      mkdir recipes mkdir artifacts\com.example.clientdevices.MyHelloWorldSubscriber\1.0.0
      PowerShell
      mkdir recipes mkdir artifacts\com.example.clientdevices.MyHelloWorldSubscriber\1.0.0
      중요

      아티팩트 폴더 경로에는 다음 형식을 사용해야 합니다. 레시피에 지정한 구성 요소 이름과 버전을 포함하십시오.

      artifacts/componentName/componentVersion/
    2. 텍스트 편집기를 사용하여 다음 내용이 포함된 구성 요소 레시피를 생성합니다. 이 레시피는 Python용 AWS IoT Device SDK v2를 설치하고 주제를 구독하고 메시지를 인쇄하는 스크립트를 실행하도록 지정합니다.

      예를 들어 Linux 기반 시스템에서는 다음 명령을 실행하여 GNU nano를 사용하여 파일을 만들 수 있습니다.

      nano recipes/com.example.clientdevices.MyHelloWorldSubscriber-1.0.0.json

      다음 레시피를 파일에 복사합니다.

      { "RecipeFormatVersion": "2020-01-25", "ComponentName": "com.example.clientdevices.MyHelloWorldSubscriber", "ComponentVersion": "1.0.0", "ComponentDescription": "A component that subscribes to Hello World messages from client devices.", "ComponentPublisher": "Amazon", "ComponentConfiguration": { "DefaultConfiguration": { "accessControl": { "aws.greengrass.ipc.pubsub": { "com.example.clientdevices.MyHelloWorldSubscriber:pubsub:1": { "policyDescription": "Allows access to subscribe to all topics.", "operations": [ "aws.greengrass#SubscribeToTopic" ], "resources": [ "*" ] } } } } }, "Manifests": [ { "Platform": { "os": "linux" }, "Lifecycle": { "install": "python3 -m pip install --user awsiotsdk", "run": "python3 -u {artifacts:path}/hello_world_subscriber.py" } }, { "Platform": { "os": "windows" }, "Lifecycle": { "install": "py -3 -m pip install --user awsiotsdk", "run": "py -3 -u {artifacts:path}/hello_world_subscriber.py" } } ] }
    3. 텍스트 편집기를 사용하여 다음 hello_world_subscriber.py 내용으로 이름이 지정된 Python 스크립트 아티팩트를 만드십시오. 이 응용 프로그램은 게시/구독 IPC 서비스를 사용하여 주제를 구독하고 clients/+/hello/world 주제를 수신한 메시지를 인쇄합니다.

      예를 들어 Linux 기반 시스템에서는 다음 명령을 실행하여 GNU nano를 사용하여 파일을 생성할 수 있습니다.

      nano artifacts/com.example.clientdevices.MyHelloWorldSubscriber/1.0.0/hello_world_subscriber.py

      다음 Python 코드를 파일에 복사합니다.

      import sys import time import traceback from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2 CLIENT_DEVICE_HELLO_WORLD_TOPIC = 'clients/+/hello/world' TIMEOUT = 10 def on_hello_world_message(event): try: message = str(event.binary_message.message, 'utf-8') print('Received new message: %s' % message) except: traceback.print_exc() try: ipc_client = GreengrassCoreIPCClientV2() # SubscribeToTopic returns a tuple with the response and the operation. _, operation = ipc_client.subscribe_to_topic( topic=CLIENT_DEVICE_HELLO_WORLD_TOPIC, on_stream_event=on_hello_world_message) print('Successfully subscribed to topic: %s' % CLIENT_DEVICE_HELLO_WORLD_TOPIC) # Keep the main thread alive, or the process will exit. try: while True: time.sleep(10) except InterruptedError: print('Subscribe interrupted.') operation.close() except Exception: print('Exception occurred when using IPC.', file=sys.stderr) traceback.print_exc() exit(1)
      참고

      이 구성 요소는 Python용 v2의 IPC 클라이언트 AWS IoT Device SDK V2를 사용하여 AWS IoT Greengrass Core 소프트웨어와 통신합니다. IPC 클라이언트 V2는 원래 IPC 클라이언트와 비교하여 사용자 지정 구성 요소에서 IPC를 사용하기 위해 작성해야 하는 코드의 양을 줄여줍니다.

    4. Greengrass CLI를 사용하여 구성 요소를 배포합니다.

      Linux or Unix
      sudo /greengrass/v2/bin/greengrass-cli deployment create \ --recipeDir recipes \ --artifactDir artifacts \ --merge "com.example.clientdevices.MyHelloWorldSubscriber=1.0.0"
      Windows Command Prompt (CMD)
      C:\greengrass\v2/bin/greengrass-cli deployment create ^ --recipeDir recipes ^ --artifactDir artifacts ^ --merge "com.example.clientdevices.MyHelloWorldSubscriber=1.0.0"
      PowerShell
      C:\greengrass\v2/bin/greengrass-cli deployment create ` --recipeDir recipes ` --artifactDir artifacts ` --merge "com.example.clientdevices.MyHelloWorldSubscriber=1.0.0"
  3. 구성 요소 로그를 보고 구성 요소가 성공적으로 설치되고 주제를 구독하는지 확인하십시오.

    Linux or Unix
    sudo tail -f /greengrass/v2/logs/com.example.clientdevices.MyHelloWorldSubscriber.log
    PowerShell
    gc C:\greengrass\v2/logs/com.example.clientdevices.MyHelloWorldSubscriber.log -Tail 10 -Wait

    로그 피드를 열어 두어 코어 장치가 메시지를 수신하는지 확인할 수 있습니다.

  4. 클라이언트 디바이스에서 샘플 Greengrass 검색 애플리케이션을 다시 실행하여 코어 디바이스로 메시지를 전송합니다.

    python3 basic_discovery.py \\ --thing_name MyClientDevice1 \\ --topic 'clients/MyClientDevice1/hello/world' \\ --message 'Hello World!' \\ --ca_file ~/certs/AmazonRootCA1.pem \\ --cert ~/certs/device.pem.crt \\ --key ~/certs/private.pem.key \\ --region us-east-1 \\ --verbosity Warn
  5. 구성 요소 로그를 다시 보고 구성 요소가 클라이언트 장치로부터 메시지를 수신하고 인쇄하는지 확인하십시오.

    Linux or Unix
    sudo tail -f /greengrass/v2/logs/com.example.clientdevices.MyHelloWorldSubscriber.log
    PowerShell
    gc C:\greengrass\v2/logs/com.example.clientdevices.MyHelloWorldSubscriber.log -Tail 10 -Wait

5단계: 클라이언트 장치 섀도우와 상호 작용하는 구성 요소 개발

클라이언트 장치의 장치 섀도우와 상호 작용하는 Greengrass 구성 요소를 개발할 수 있습니다. AWS IoT 섀도우는 클라이언트 장치와 같은 사물에 대한 현재 또는 원하는 상태 정보를 저장하는 JSON 문서입니다. AWS IoT 사용자 지정 구성 요소는 클라이언트 장치가 연결되어 있지 않은 경우에도 클라이언트 장치의 섀도에 액세스하여 상태를 관리할 수 있습니다. AWS IoT 각 AWS IoT 오브젝트에는 이름이 지정되지 않은 섀도우가 있으며, 각 오브젝트에 대해 이름이 지정된 섀도우를 여러 개 만들 수도 있습니다.

이 섹션에서는 섀도우 관리자 컴포넌트를 배포하여 코어 디바이스의 섀도우를 관리합니다. 또한 MQTT 브리지 구성 요소를 업데이트하여 클라이언트 장치와 섀도우 관리자 구성 요소 간에 섀도우 메시지를 릴레이할 수 있습니다. 그런 다음 클라이언트 장치의 섀도를 업데이트하는 구성 요소를 개발하고 구성 요소의 섀도우 업데이트에 응답하는 샘플 응용 프로그램을 클라이언트 장치에서 실행합니다. 이 구성 요소는 핵심 장치가 클라이언트 장치로 연결되는 스마트 조명의 색상 상태를 관리하는 스마트 조명 관리 응용 프로그램을 나타냅니다.

클라이언트 장치 섀도우와 상호 작용하는 구성 요소 개발
  1. 배포를 코어 장치로 수정하여 섀도우 관리자 구성 요소를 배포하고, 클라이언트 장치와 섀도우 관리자가 통신하는 로컬 게시/구독 간에 섀도우 메시지를 릴레이하도록 MQTT 브리지 구성 요소를 구성합니다. 다음을 따릅니다.

    1. 왼쪽 탐색 메뉴에서 Core devices를 선택합니다.

    2. 코어 디바이스 페이지에서 이 튜토리얼에 사용 중인 코어 디바이스를 선택합니다.

    3. 코어 장치 세부 정보 페이지에서 클라이언트 장치 탭을 선택합니다.

    4. 클라이언트 디바이스 탭에서 클라우드 검색 구성을 선택합니다.

      코어 디바이스 검색 구성 페이지가 열립니다. 이 페이지에서 코어 장치에 배포할 클라이언트 장치 구성 요소를 변경하거나 구성할 수 있습니다.

    5. 3단계에서 aws.greengrass.clientdevices.mqtt.Bridge구성 요소에 대해 구성 편집을 선택합니다.

    6. MQTT 브리지 구성 요소의 구성 편집 모달에서 클라이언트 장치와 로컬 게시/구독 인터페이스 간에 장치 섀도우 주제에 대한 MQTT 메시지를 릴레이하는 주제 매핑을 구성합니다. 또한 배포에 호환되는 MQTT 브리지 버전이 지정되어 있는지 확인합니다. 클라이언트 디바이스 섀도를 지원하려면 MQTT 브리지 v2.2.0 이상이 필요합니다. 다음을 따릅니다.

      1. 구성 요소 버전의 경우 버전 2.2.0 이상을 선택하십시오.

      2. 구성의 코드를 병합할 구성 블록에 다음 구성을 입력합니다. 이 구성은 섀도우 주제에 대해 MQTT 메시지를 릴레이하도록 지정합니다.

        { "mqttTopicMapping": { "HelloWorldIotCoreMapping": { "topic": "clients/+/hello/world", "source": "LocalMqtt", "target": "IotCore" }, "HelloWorldPubsubMapping": { "topic": "clients/+/hello/world", "source": "LocalMqtt", "target": "Pubsub" }, "ShadowsLocalMqttToPubsub": { "topic": "$aws/things/+/shadow/#", "source": "LocalMqtt", "target": "Pubsub" }, "ShadowsPubsubToLocalMqtt": { "topic": "$aws/things/+/shadow/#", "source": "Pubsub", "target": "LocalMqtt" } } }

        자세한 내용은 MQTT 브리지 구성 요소 구성을 참조하십시오.

      3. 확인을 선택합니다.

    7. 3단계에서 배포할 aws.greengrass.ShadowManager구성 요소를 선택합니다.

    8. 검토 및 배포를 선택하여 이 페이지에서 생성한 배포를 검토하십시오.

    9. 검토 페이지에서 [Deploy] 를 선택하여 코어 장치에 대한 배포를 시작합니다.

    10. 배포가 성공했는지 확인하려면 배포 상태를 확인하고 코어 장치의 로그를 확인하십시오. 코어 디바이스의 배포 상태를 확인하려면 배포 개요에서 타겟을 선택하면 됩니다. 자세한 내용은 다음 자료를 참조하세요.

  2. 스마트 조명 클라이언트 장치를 관리하는 Greengrass 구성 요소를 개발하고 배포하십시오. 다음을 따릅니다.

    1. 코어 디바이스에 컴포넌트의 아티팩트가 들어 있는 폴더를 생성합니다.

      Linux or Unix
      mkdir -p artifacts/com.example.clientdevices.MySmartLightManager/1.0.0
      Windows Command Prompt (CMD)
      mkdir artifacts\com.example.clientdevices.MySmartLightManager\1.0.0
      PowerShell
      mkdir artifacts\com.example.clientdevices.MySmartLightManager\1.0.0
      중요

      아티팩트 폴더 경로에는 다음 형식을 사용해야 합니다. 레시피에 지정한 구성 요소 이름과 버전을 포함하십시오.

      artifacts/componentName/componentVersion/
    2. 텍스트 편집기를 사용하여 다음 내용이 포함된 구성 요소 레시피를 생성합니다. 이 레시피는 Python용 AWS IoT Device SDK v2를 설치하고 스마트 조명 클라이언트 장치의 그림자와 상호 작용하여 색상을 관리하는 스크립트를 실행하도록 지정합니다.

      예를 들어 Linux 기반 시스템에서는 다음 명령을 실행하여 GNU nano를 사용하여 파일을 만들 수 있습니다.

      nano recipes/com.example.clientdevices.MySmartLightManager-1.0.0.json

      다음 레시피를 파일에 복사합니다.

      { "RecipeFormatVersion": "2020-01-25", "ComponentName": "com.example.clientdevices.MySmartLightManager", "ComponentVersion": "1.0.0", "ComponentDescription": "A component that interacts with smart light client devices.", "ComponentPublisher": "Amazon", "ComponentDependencies": { "aws.greengrass.Nucleus": { "VersionRequirement": "^2.6.0" }, "aws.greengrass.ShadowManager": { "VersionRequirement": "^2.2.0" }, "aws.greengrass.clientdevices.mqtt.Bridge": { "VersionRequirement": "^2.2.0" } }, "ComponentConfiguration": { "DefaultConfiguration": { "smartLightDeviceNames": [], "accessControl": { "aws.greengrass.ShadowManager": { "com.example.clientdevices.MySmartLightManager:shadow:1": { "policyDescription": "Allows access to client devices' unnamed shadows", "operations": [ "aws.greengrass#GetThingShadow", "aws.greengrass#UpdateThingShadow" ], "resources": [ "$aws/things/MyClientDevice*/shadow" ] } }, "aws.greengrass.ipc.pubsub": { "com.example.clientdevices.MySmartLightManager:pubsub:1": { "policyDescription": "Allows access to client devices' unnamed shadow updates", "operations": [ "aws.greengrass#SubscribeToTopic" ], "resources": [ "$aws/things/+/shadow/update/accepted" ] } } } } }, "Manifests": [ { "Platform": { "os": "linux" }, "Lifecycle": { "install": "python3 -m pip install --user awsiotsdk", "run": "python3 -u {artifacts:path}/smart_light_manager.py" } }, { "Platform": { "os": "windows" }, "Lifecycle": { "install": "py -3 -m pip install --user awsiotsdk", "run": "py -3 -u {artifacts:path}/smart_light_manager.py" } } ] }
    3. 텍스트 편집기를 사용하여 다음 smart_light_manager.py 내용으로 이름이 지정된 Python 스크립트 아티팩트를 만드십시오. 이 애플리케이션은 섀도우 IPC 서비스를 사용하여 클라이언트 디바이스 섀도를 가져오고 업데이트하고 로컬 게시/구독 IPC 서비스를 사용하여 보고된 섀도우 업데이트를 수신합니다.

      예를 들어, Linux 기반 시스템에서는 다음 명령을 실행하여 GNU nano를 사용하여 파일을 생성할 수 있습니다.

      nano artifacts/com.example.clientdevices.MySmartLightManager/1.0.0/smart_light_manager.py

      다음 Python 코드를 파일에 복사합니다.

      import json import random import sys import time import traceback from uuid import uuid4 from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2 from awsiot.greengrasscoreipc.model import ResourceNotFoundError SHADOW_COLOR_PROPERTY = 'color' CONFIGURATION_CLIENT_DEVICE_NAMES = 'smartLightDeviceNames' COLORS = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'] SHADOW_UPDATE_TOPIC = '$aws/things/+/shadow/update/accepted' SET_COLOR_INTERVAL = 15 class SmartLightDevice(): def __init__(self, client_device_name: str, reported_color: str = None): self.name = client_device_name self.reported_color = reported_color self.desired_color = None class SmartLightDeviceManager(): def __init__(self, ipc_client: GreengrassCoreIPCClientV2): self.ipc_client = ipc_client self.devices = {} self.client_tokens = set() self.shadow_update_accepted_subscription_operation = None self.client_device_names_configuration_subscription_operation = None self.update_smart_light_device_list() def update_smart_light_device_list(self): # Update the device list from the component configuration. response = self.ipc_client.get_configuration( key_path=[CONFIGURATION_CLIENT_DEVICE_NAMES]) # Identify the difference between the configuration and the currently tracked devices. current_device_names = self.devices.keys() updated_device_names = response.value[CONFIGURATION_CLIENT_DEVICE_NAMES] added_device_names = set(updated_device_names) - set(current_device_names) removed_device_names = set(current_device_names) - set(updated_device_names) # Stop tracking any smart light devices that are no longer in the configuration. for name in removed_device_names: print('Removing %s from smart light device manager' % name) self.devices.pop(name) # Start tracking any new smart light devices that are in the configuration. for name in added_device_names: print('Adding %s to smart light device manager' % name) device = SmartLightDevice(name) device.reported_color = self.get_device_reported_color(device) self.devices[name] = device print('Current color for %s is %s' % (name, device.reported_color)) def get_device_reported_color(self, smart_light_device): try: response = self.ipc_client.get_thing_shadow( thing_name=smart_light_device.name, shadow_name='') shadow = json.loads(str(response.payload, 'utf-8')) if 'reported' in shadow['state']: return shadow['state']['reported'].get(SHADOW_COLOR_PROPERTY) return None except ResourceNotFoundError: return None def request_device_color_change(self, smart_light_device, color): # Generate and track a client token for the request. client_token = str(uuid4()) self.client_tokens.add(client_token) # Create a shadow payload, which must be a blob. payload_json = { 'state': { 'desired': { SHADOW_COLOR_PROPERTY: color } }, 'clientToken': client_token } payload = bytes(json.dumps(payload_json), 'utf-8') self.ipc_client.update_thing_shadow( thing_name=smart_light_device.name, shadow_name='', payload=payload) smart_light_device.desired_color = color def subscribe_to_shadow_update_accepted_events(self): if self.shadow_update_accepted_subscription_operation == None: # SubscribeToTopic returns a tuple with the response and the operation. _, self.shadow_update_accepted_subscription_operation = self.ipc_client.subscribe_to_topic( topic=SHADOW_UPDATE_TOPIC, on_stream_event=self.on_shadow_update_accepted_event) print('Successfully subscribed to shadow update accepted topic') def close_shadow_update_accepted_subscription(self): if self.shadow_update_accepted_subscription_operation is not None: self.shadow_update_accepted_subscription_operation.close() def on_shadow_update_accepted_event(self, event): try: message = str(event.binary_message.message, 'utf-8') accepted_payload = json.loads(message) # Check for reported states from smart light devices and ignore desired states from components. if 'reported' in accepted_payload['state']: # Process this update only if it uses a client token created by this component. client_token = accepted_payload.get('clientToken') if client_token is not None and client_token in self.client_tokens: self.client_tokens.remove(client_token) shadow_state = accepted_payload['state']['reported'] if SHADOW_COLOR_PROPERTY in shadow_state: reported_color = shadow_state[SHADOW_COLOR_PROPERTY] topic = event.binary_message.context.topic client_device_name = topic.split('/')[2] if client_device_name in self.devices: # Set the reported color for the smart light device. self.devices[client_device_name].reported_color = reported_color print( 'Received shadow update confirmation from client device: %s' % client_device_name) else: print("Shadow update doesn't specify color") except: traceback.print_exc() def subscribe_to_client_device_name_configuration_updates(self): if self.client_device_names_configuration_subscription_operation == None: # SubscribeToConfigurationUpdate returns a tuple with the response and the operation. _, self.client_device_names_configuration_subscription_operation = self.ipc_client.subscribe_to_configuration_update( key_path=[CONFIGURATION_CLIENT_DEVICE_NAMES], on_stream_event=self.on_client_device_names_configuration_update_event) print( 'Successfully subscribed to configuration updates for smart light device names') def close_client_device_names_configuration_subscription(self): if self.client_device_names_configuration_subscription_operation is not None: self.client_device_names_configuration_subscription_operation.close() def on_client_device_names_configuration_update_event(self, event): try: if CONFIGURATION_CLIENT_DEVICE_NAMES in event.configuration_update_event.key_path: print('Received configuration update for list of client devices') self.update_smart_light_device_list() except: traceback.print_exc() def choose_random_color(): return random.choice(COLORS) def main(): try: # Create an IPC client and a smart light device manager. ipc_client = GreengrassCoreIPCClientV2() smart_light_manager = SmartLightDeviceManager(ipc_client) smart_light_manager.subscribe_to_shadow_update_accepted_events() smart_light_manager.subscribe_to_client_device_name_configuration_updates() try: # Keep the main thread alive, or the process will exit. while True: # Set each smart light device to a random color at a regular interval. for device_name in smart_light_manager.devices: device = smart_light_manager.devices[device_name] desired_color = choose_random_color() print('Chose random color (%s) for %s' % (desired_color, device_name)) if desired_color == device.desired_color: print('Desired color for %s is already %s' % (device_name, desired_color)) elif desired_color == device.reported_color: print('Reported color for %s is already %s' % (device_name, desired_color)) else: smart_light_manager.request_device_color_change( device, desired_color) print('Requested color change for %s to %s' % (device_name, desired_color)) time.sleep(SET_COLOR_INTERVAL) except InterruptedError: print('Application interrupted') smart_light_manager.close_shadow_update_accepted_subscription() smart_light_manager.close_client_device_names_configuration_subscription() except Exception: print('Exception occurred', file=sys.stderr) traceback.print_exc() exit(1) if __name__ == '__main__': main()

      이 Python 응용 프로그램은 다음을 수행합니다.

      • 구성 요소의 구성을 읽고 관리할 스마트 조명 클라이언트 장치 목록을 가져옵니다.

      • SubscribeToConfigurationUpdateIPC 작업을 사용하여 구성 업데이트 알림을 구독합니다. AWS IoT GreengrassCore 소프트웨어는 구성 요소의 구성이 변경될 때마다 알림을 보냅니다. 구성 요소가 구성 업데이트 알림을 받으면 구성 요소가 관리하는 스마트 조명 클라이언트 장치 목록을 업데이트합니다.

      • 각 스마트 조명 클라이언트 장치의 섀도우를 가져와 초기 색상 상태를 가져옵니다.

      • 각 스마트 조명 클라이언트 장치의 색상을 15초마다 임의의 색상으로 설정합니다. 컴포넌트는 클라이언트 디바이스의 사물 섀도우를 업데이트하여 색상을 변경합니다. 이 작업은 MQTT를 통해 클라이언트 디바이스에 섀도우 델타 이벤트를 전송합니다.

      • IPC 작업을 사용하여 로컬 게시/구독 인터페이스에서 섀도우 업데이트 허용 메시지를 구독합니다. SubscribeToTopic 이 구성 요소는 이러한 메시지를 수신하여 각 스마트 조명 클라이언트 장치의 색상을 추적합니다. 스마트 조명 클라이언트 장치가 섀도우 업데이트를 수신하면 MQTT 메시지를 보내 업데이트를 받았는지 확인합니다. MQTT 브리지는 이 메시지를 로컬 게시/구독 인터페이스로 전달합니다.

    4. Greengrass CLI를 사용하여 구성 요소를 배포합니다. 이 구성 요소를 배포할 때는 섀도우를 관리하는 클라이언트 장치 목록을 지정합니다. smartLightDeviceNames MyClientDevice1을 클라이언트 디바이스의 사물 이름으로 바꾸십시오.

      Linux or Unix
      sudo /greengrass/v2/bin/greengrass-cli deployment create \ --recipeDir recipes \ --artifactDir artifacts \ --merge "com.example.clientdevices.MySmartLightManager=1.0.0" \ --update-config '{ "com.example.clientdevices.MySmartLightManager": { "MERGE": { "smartLightDeviceNames": [ "MyClientDevice1" ] } } }'
      Windows Command Prompt (CMD)
      C:\greengrass\v2/bin/greengrass-cli deployment create ^ --recipeDir recipes ^ --artifactDir artifacts ^ --merge "com.example.clientdevices.MySmartLightManager=1.0.0" ^ --update-config '{"com.example.clientdevices.MySmartLightManager":{"MERGE":{"smartLightDeviceNames":["MyClientDevice1"]}}}'
      PowerShell
      C:\greengrass\v2/bin/greengrass-cli deployment create ` --recipeDir recipes ` --artifactDir artifacts ` --merge "com.example.clientdevices.MySmartLightManager=1.0.0" ` --update-config '{ "com.example.clientdevices.MySmartLightManager": { "MERGE": { "smartLightDeviceNames": [ "MyClientDevice1" ] } } }'
  3. 구성 요소 로그를 보고 구성 요소가 성공적으로 설치되고 실행되는지 확인합니다.

    Linux or Unix
    sudo tail -f /greengrass/v2/logs/com.example.clientdevices.MySmartLightManager.log
    PowerShell
    gc C:\greengrass\v2/logs/com.example.clientdevices.MySmartLightManager.log -Tail 10 -Wait

    구성 요소가 스마트 조명 클라이언트 장치의 색상 변경 요청을 보냅니다. 섀도우 관리자는 요청을 수신하고 섀도우의 desired 상태를 설정합니다. 하지만 스마트 라이트 클라이언트 장치가 아직 실행되고 있지 않으므로 섀도우의 reported 상태는 변경되지 않습니다. 구성 요소 로그에는 다음 메시지가 포함됩니다.

    2022-07-07T03:49:24.908Z [INFO] (Copier) com.example.clientdevices.MySmartLightManager: stdout. Chose random color (blue) for MyClientDevice1. {scriptName=services.com.example.clientdevices.MySmartLightManager.lifecycle.Run, serviceName=com.example.clientdevices.MySmartLightManager, currentState=RUNNING} 2022-07-07T03:49:24.912Z [INFO] (Copier) com.example.clientdevices.MySmartLightManager: stdout. Requested color change for MyClientDevice1 to blue. {scriptName=services.com.example.clientdevices.MySmartLightManager.lifecycle.Run, serviceName=com.example.clientdevices.MySmartLightManager, currentState=RUNNING}

    로그 피드를 열어 두고 구성 요소가 메시지를 인쇄하는 시기를 확인할 수 있습니다.

  4. Greengrass Discovery를 사용하고 디바이스 섀도 업데이트를 구독하는 샘플 애플리케이션을 다운로드하여 실행하십시오. 클라이언트 디바이스에서 다음을 수행하십시오.

    1. Python용 AWS IoT Device SDK v2의 샘플 폴더로 변경합니다. 이 샘플 애플리케이션은 samples 폴더의 명령줄 파싱 모듈을 사용합니다.

      cd aws-iot-device-sdk-python-v2/samples
    2. 텍스트 편집기를 사용하여 다음 basic_discovery_shadow.py 내용으로 이름이 지정된 Python 스크립트를 작성하십시오. 이 애플리케이션은 Greengrass 검색 및 섀도를 사용하여 클라이언트 디바이스와 코어 디바이스 간에 속성을 동기화된 상태로 유지합니다.

      예를 들어 Linux 기반 시스템에서는 다음 명령을 실행하여 GNU nano를 사용하여 파일을 생성할 수 있습니다.

      nano basic_discovery_shadow.py

      다음 Python 코드를 파일에 복사합니다.

      # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. from awscrt import io from awscrt import mqtt from awsiot import iotshadow from awsiot.greengrass_discovery import DiscoveryClient from awsiot import mqtt_connection_builder from concurrent.futures import Future import sys import threading import traceback from uuid import uuid4 # Parse arguments import utils.command_line_utils; cmdUtils = utils.command_line_utils.CommandLineUtils("Basic Discovery - Greengrass discovery example with device shadows.") cmdUtils.add_common_mqtt_commands() cmdUtils.add_common_topic_message_commands() cmdUtils.add_common_logging_commands() cmdUtils.register_command("key", "<path>", "Path to your key in PEM format.", True, str) cmdUtils.register_command("cert", "<path>", "Path to your client certificate in PEM format.", True, str) cmdUtils.remove_command("endpoint") cmdUtils.register_command("thing_name", "<str>", "The name assigned to your IoT Thing", required=True) cmdUtils.register_command("region", "<str>", "The region to connect through.", required=True) cmdUtils.register_command("shadow_property", "<str>", "The name of the shadow property you want to change (optional, default='color'", default="color") # Needs to be called so the command utils parse the commands cmdUtils.get_args() # Using globals to simplify sample code is_sample_done = threading.Event() mqtt_connection = None shadow_thing_name = cmdUtils.get_command_required("thing_name") shadow_property = cmdUtils.get_command("shadow_property") SHADOW_VALUE_DEFAULT = "off" class LockedData: def __init__(self): self.lock = threading.Lock() self.shadow_value = None self.disconnect_called = False self.request_tokens = set() locked_data = LockedData() def on_connection_interupted(connection, error, **kwargs): print('connection interrupted with error {}'.format(error)) def on_connection_resumed(connection, return_code, session_present, **kwargs): print('connection resumed with return code {}, session present {}'.format(return_code, session_present)) # Try IoT endpoints until we find one that works def try_iot_endpoints(): for gg_group in discover_response.gg_groups: for gg_core in gg_group.cores: for connectivity_info in gg_core.connectivity: try: print('Trying core {} at host {} port {}'.format(gg_core.thing_arn, connectivity_info.host_address, connectivity_info.port)) mqtt_connection = mqtt_connection_builder.mtls_from_path( endpoint=connectivity_info.host_address, port=connectivity_info.port, cert_filepath=cmdUtils.get_command_required("cert"), pri_key_filepath=cmdUtils.get_command_required("key"), ca_bytes=gg_group.certificate_authorities[0].encode('utf-8'), on_connection_interrupted=on_connection_interupted, on_connection_resumed=on_connection_resumed, client_id=cmdUtils.get_command_required("thing_name"), clean_session=False, keep_alive_secs=30) connect_future = mqtt_connection.connect() connect_future.result() print('Connected!') return mqtt_connection except Exception as e: print('Connection failed with exception {}'.format(e)) continue exit('All connection attempts failed') # Function for gracefully quitting this sample def exit(msg_or_exception): if isinstance(msg_or_exception, Exception): print("Exiting sample due to exception.") traceback.print_exception(msg_or_exception.__class__, msg_or_exception, sys.exc_info()[2]) else: print("Exiting sample:", msg_or_exception) with locked_data.lock: if not locked_data.disconnect_called: print("Disconnecting...") locked_data.disconnect_called = True future = mqtt_connection.disconnect() future.add_done_callback(on_disconnected) def on_disconnected(disconnect_future): # type: (Future) -> None print("Disconnected.") # Signal that sample is finished is_sample_done.set() def on_get_shadow_accepted(response): # type: (iotshadow.GetShadowResponse) -> None try: with locked_data.lock: # check that this is a response to a request from this session try: locked_data.request_tokens.remove(response.client_token) except KeyError: return print("Finished getting initial shadow state.") if locked_data.shadow_value is not None: print(" Ignoring initial query because a delta event has already been received.") return if response.state: if response.state.delta: value = response.state.delta.get(shadow_property) if value: print(" Shadow contains delta value '{}'.".format(value)) change_shadow_value(value) return if response.state.reported: value = response.state.reported.get(shadow_property) if value: print(" Shadow contains reported value '{}'.".format(value)) set_local_value_due_to_initial_query(response.state.reported[shadow_property]) return print(" Shadow document lacks '{}' property. Setting defaults...".format(shadow_property)) change_shadow_value(SHADOW_VALUE_DEFAULT) return except Exception as e: exit(e) def on_get_shadow_rejected(error): # type: (iotshadow.ErrorResponse) -> None try: # check that this is a response to a request from this session with locked_data.lock: try: locked_data.request_tokens.remove(error.client_token) except KeyError: return if error.code == 404: print("Thing has no shadow document. Creating with defaults...") change_shadow_value(SHADOW_VALUE_DEFAULT) else: exit("Get request was rejected. code:{} message:'{}'".format( error.code, error.message)) except Exception as e: exit(e) def on_shadow_delta_updated(delta): # type: (iotshadow.ShadowDeltaUpdatedEvent) -> None try: print("Received shadow delta event.") if delta.state and (shadow_property in delta.state): value = delta.state[shadow_property] if value is None: print(" Delta reports that '{}' was deleted. Resetting defaults...".format(shadow_property)) change_shadow_value(SHADOW_VALUE_DEFAULT) return else: print(" Delta reports that desired value is '{}'. Changing local value...".format(value)) if (delta.client_token is not None): print (" ClientToken is: " + delta.client_token) change_shadow_value(value, delta.client_token) else: print(" Delta did not report a change in '{}'".format(shadow_property)) except Exception as e: exit(e) def on_publish_update_shadow(future): #type: (Future) -> None try: future.result() print("Update request published.") except Exception as e: print("Failed to publish update request.") exit(e) def on_update_shadow_accepted(response): # type: (iotshadow.UpdateShadowResponse) -> None try: # check that this is a response to a request from this session with locked_data.lock: try: locked_data.request_tokens.remove(response.client_token) except KeyError: return try: if response.state.reported != None: if shadow_property in response.state.reported: print("Finished updating reported shadow value to '{}'.".format(response.state.reported[shadow_property])) # type: ignore else: print ("Could not find shadow property with name: '{}'.".format(shadow_property)) # type: ignore else: print("Shadow states cleared.") # when the shadow states are cleared, reported and desired are set to None except: exit("Updated shadow is missing the target property") except Exception as e: exit(e) def on_update_shadow_rejected(error): # type: (iotshadow.ErrorResponse) -> None try: # check that this is a response to a request from this session with locked_data.lock: try: locked_data.request_tokens.remove(error.client_token) except KeyError: return exit("Update request was rejected. code:{} message:'{}'".format( error.code, error.message)) except Exception as e: exit(e) def set_local_value_due_to_initial_query(reported_value): with locked_data.lock: locked_data.shadow_value = reported_value def change_shadow_value(value, token=None): with locked_data.lock: if locked_data.shadow_value == value: print("Local value is already '{}'.".format(value)) return print("Changed local shadow value to '{}'.".format(value)) locked_data.shadow_value = value print("Updating reported shadow value to '{}'...".format(value)) reuse_token = token is not None # use a unique token so we can correlate this "request" message to # any "response" messages received on the /accepted and /rejected topics if not reuse_token: token = str(uuid4()) # if the value is "clear shadow" then send a UpdateShadowRequest with None # for both reported and desired to clear the shadow document completely. if value == "clear_shadow": tmp_state = iotshadow.ShadowState(reported=None, desired=None, reported_is_nullable=True, desired_is_nullable=True) request = iotshadow.UpdateShadowRequest( thing_name=shadow_thing_name, state=tmp_state, client_token=token, ) # Otherwise, send a normal update request else: # if the value is "none" then set it to a Python none object to # clear the individual shadow property if value == "none": value = None request = iotshadow.UpdateShadowRequest( thing_name=shadow_thing_name, state=iotshadow.ShadowState( reported={ shadow_property: value } ), client_token=token, ) future = shadow_client.publish_update_shadow(request, mqtt.QoS.AT_LEAST_ONCE) if not reuse_token: locked_data.request_tokens.add(token) future.add_done_callback(on_publish_update_shadow) if __name__ == '__main__': tls_options = io.TlsContextOptions.create_client_with_mtls_from_path(cmdUtils.get_command_required("cert"), cmdUtils.get_command_required("key")) if cmdUtils.get_command(cmdUtils.m_cmd_ca_file): tls_options.override_default_trust_store_from_path(None, cmdUtils.get_command(cmdUtils.m_cmd_ca_file)) tls_context = io.ClientTlsContext(tls_options) socket_options = io.SocketOptions() print('Performing greengrass discovery...') discovery_client = DiscoveryClient(io.ClientBootstrap.get_or_create_static_default(), socket_options, tls_context, cmdUtils.get_command_required("region")) resp_future = discovery_client.discover(cmdUtils.get_command_required("thing_name")) discover_response = resp_future.result() print(discover_response) if cmdUtils.get_command("print_discover_resp_only"): exit(0) mqtt_connection = try_iot_endpoints() shadow_client = iotshadow.IotShadowClient(mqtt_connection) try: # Subscribe to necessary topics. # Note that is **is** important to wait for "accepted/rejected" subscriptions # to succeed before publishing the corresponding "request". print("Subscribing to Update responses...") update_accepted_subscribed_future, _ = shadow_client.subscribe_to_update_shadow_accepted( request=iotshadow.UpdateShadowSubscriptionRequest(thing_name=shadow_thing_name), qos=mqtt.QoS.AT_LEAST_ONCE, callback=on_update_shadow_accepted) update_rejected_subscribed_future, _ = shadow_client.subscribe_to_update_shadow_rejected( request=iotshadow.UpdateShadowSubscriptionRequest(thing_name=shadow_thing_name), qos=mqtt.QoS.AT_LEAST_ONCE, callback=on_update_shadow_rejected) # Wait for subscriptions to succeed update_accepted_subscribed_future.result() update_rejected_subscribed_future.result() print("Subscribing to Get responses...") get_accepted_subscribed_future, _ = shadow_client.subscribe_to_get_shadow_accepted( request=iotshadow.GetShadowSubscriptionRequest(thing_name=shadow_thing_name), qos=mqtt.QoS.AT_LEAST_ONCE, callback=on_get_shadow_accepted) get_rejected_subscribed_future, _ = shadow_client.subscribe_to_get_shadow_rejected( request=iotshadow.GetShadowSubscriptionRequest(thing_name=shadow_thing_name), qos=mqtt.QoS.AT_LEAST_ONCE, callback=on_get_shadow_rejected) # Wait for subscriptions to succeed get_accepted_subscribed_future.result() get_rejected_subscribed_future.result() print("Subscribing to Delta events...") delta_subscribed_future, _ = shadow_client.subscribe_to_shadow_delta_updated_events( request=iotshadow.ShadowDeltaUpdatedSubscriptionRequest(thing_name=shadow_thing_name), qos=mqtt.QoS.AT_LEAST_ONCE, callback=on_shadow_delta_updated) # Wait for subscription to succeed delta_subscribed_future.result() # The rest of the sample runs asynchronously. # Issue request for shadow's current state. # The response will be received by the on_get_accepted() callback print("Requesting current shadow state...") with locked_data.lock: # use a unique token so we can correlate this "request" message to # any "response" messages received on the /accepted and /rejected topics token = str(uuid4()) publish_get_future = shadow_client.publish_get_shadow( request=iotshadow.GetShadowRequest(thing_name=shadow_thing_name, client_token=token), qos=mqtt.QoS.AT_LEAST_ONCE) locked_data.request_tokens.add(token) # Ensure that publish succeeds publish_get_future.result() except Exception as e: exit(e) # Wait for the sample to finish (user types 'quit', or an error occurs) is_sample_done.wait()

      이 Python 응용 프로그램은 다음을 수행합니다.

      • Greengrass 디스커버리를 사용하여 코어 디바이스를 검색하고 연결합니다.

      • 코어 디바이스에 섀도우 문서를 요청하여 속성의 초기 상태를 가져옵니다.

      • 섀도우 델타 이벤트를 구독합니다. 섀도우 델타 이벤트는 속성 desired 값이 해당 값과 다를 때 코어 디바이스가 전송합니다reported. 애플리케이션은 섀도우 델타 이벤트를 수신하면 속성 값을 변경하고 코어 디바이스에 업데이트를 전송하여 새 값을 해당 reported 값으로 설정합니다.

      이 애플리케이션은 Greengrass 디스커버리와 v2의 섀도우 샘플을 결합합니다. AWS IoT Device SDK

    3. 샘플 애플리케이션을 실행합니다. 이 응용 프로그램에는 클라이언트 장치 사물 이름, 사용할 섀도우 속성, 연결을 인증하고 보호하는 인증서를 지정하는 인수가 필요합니다.

      • MyClientDevice1을 클라이언트 디바이스의 사물 이름으로 바꾸십시오.

      • ~/certs/ AmazonRoot ca1.pem을 클라이언트 디바이스의 Amazon 루트 CA 인증서 경로로 바꾸십시오.

      • ~/certs/device.pem.crt를 클라이언트 디바이스의 디바이스 인증서 경로로 바꾸십시오.

      • ~/certs/private.pem.key를 클라이언트 장치의 개인 키 파일 경로로 바꾸십시오.

      • us-east-1을 클라이언트 디바이스 및 코어 디바이스가 운영되는 지역으로 바꾸십시오. AWS

      python3 basic_discovery_shadow.py \ --thing_name MyClientDevice1 \ --shadow_property color \ --ca_file ~/certs/AmazonRootCA1.pem \ --cert ~/certs/device.pem.crt \ --key ~/certs/private.pem.key \ --region us-east-1 \ --verbosity Warn

      샘플 애플리케이션은 섀도우 토픽을 구독하고 코어 디바이스로부터 섀도우 델타 이벤트를 수신할 때까지 기다립니다. 애플리케이션이 섀도 델타 이벤트를 수신하고 이에 응답한다는 결과가 출력에 표시되면 클라이언트 디바이스는 코어 디바이스의 섀도우와 성공적으로 상호 작용할 수 있습니다.

      Performing greengrass discovery... awsiot.greengrass_discovery.DiscoverResponse(gg_groups=[awsiot.greengrass_discovery.GGGroup(gg_group_id='greengrassV2-coreDevice-MyGreengrassCore', cores=[awsiot.greengrass_discovery.GGCore(thing_arn='arn:aws:iot:us-east-1:123456789012:thing/MyGreengrassCore', connectivity=[awsiot.greengrass_discovery.ConnectivityInfo(id='203.0.113.0', host_address='203.0.113.0', metadata='', port=8883)])], certificate_authorities=['-----BEGIN CERTIFICATE-----\nMIICiT...EXAMPLE=\n-----END CERTIFICATE-----\n'])]) Trying core arn:aws:iot:us-east-1:123456789012:thing/MyGreengrassCore at host 203.0.113.0 port 8883 Connected! Subscribing to Update responses... Subscribing to Get responses... Subscribing to Delta events... Requesting current shadow state... Received shadow delta event. Delta reports that desired value is 'purple'. Changing local value... ClientToken is: 3dce4d3f-e336-41ac-aa4f-7882725f0033 Changed local shadow value to 'purple'. Updating reported shadow value to 'purple'... Update request published.

      애플리케이션이 대신 오류를 출력하는 경우 Greengrass 검색 문제 해결을 참조하십시오.

      또한 코어 디바이스의 Greengrass 로그를 확인하여 클라이언트 디바이스가 성공적으로 연결하고 메시지를 전송하는지 확인할 수 있습니다. 자세한 설명은 모니터 AWS IoT Greengrass 로그 섹션을 참조하세요.

  5. 구성 요소 로그를 다시 보고 구성 요소가 스마트 조명 클라이언트 장치로부터 섀도우 업데이트 확인을 수신하는지 확인하십시오.

    Linux or Unix
    sudo tail -f /greengrass/v2/logs/com.example.clientdevices.MySmartLightManager.log
    PowerShell
    gc C:\greengrass\v2/logs/com.example.clientdevices.MySmartLightManager.log -Tail 10 -Wait

    구성 요소는 메시지를 기록하여 스마트 조명 클라이언트 장치의 색상이 변경되었음을 확인합니다.

    2022-07-07T03:49:24.908Z [INFO] (Copier) com.example.clientdevices.MySmartLightManager: stdout. Chose random color (blue) for MyClientDevice1. {scriptName=services.com.example.clientdevices.MySmartLightManager.lifecycle.Run, serviceName=com.example.clientdevices.MySmartLightManager, currentState=RUNNING} 2022-07-07T03:49:24.912Z [INFO] (Copier) com.example.clientdevices.MySmartLightManager: stdout. Requested color change for MyClientDevice1 to blue. {scriptName=services.com.example.clientdevices.MySmartLightManager.lifecycle.Run, serviceName=com.example.clientdevices.MySmartLightManager, currentState=RUNNING} 2022-07-07T03:49:24.959Z [INFO] (Copier) com.example.clientdevices.MySmartLightManager: stdout. Received shadow update confirmation from client device: MyClientDevice1. {scriptName=services.com.example.clientdevices.MySmartLightManager.lifecycle.Run, serviceName=com.example.clientdevices.MySmartLightManager, currentState=RUNNING}
참고

클라이언트 디바이스의 섀도우는 코어 디바이스와 클라이언트 디바이스 간에 동기화됩니다. 하지만 코어 디바이스는 클라이언트 디바이스의 섀도우를 동기화하지 않습니다AWS IoT Core. 예를 들어 AWS IoT Core 섀도우를 동기화하여 플릿에 있는 모든 디바이스의 상태를 보거나 수정할 수 있습니다. 섀도우를 동기화하도록 섀도우 관리자 컴포넌트를 구성하는 방법에 대한 자세한 내용은 을 AWS IoT Core 참조하십시오로컬 장치 섀도우를 다음과 동기화합니다. AWS IoT Core.

이 튜토리얼을 완료했습니다. 클라이언트 디바이스는 코어 디바이스에 연결하고, Greengrass 컴포넌트에 MQTT 메시지를 AWS IoT Core 전송하고, 코어 디바이스로부터 섀도우 업데이트를 수신합니다. 이 자습서에서 다루는 주제에 대한 자세한 내용은 다음을 참조하십시오.