

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

# V2에서 V1 애플리케이션을 테스트할 새 디바이스 설정
<a name="set-up-test-device"></a>

프로덕션 디바이스에 대한 위험을 최소화하려면 프로덕션 디바이스를 업그레이드하기 전에 V2에서 VV1 애플리케이션을 테스트할 새 디바이스를 생성합니다.

이전 단계의 런타임 선택에 따라 다음 설정 가이드 중 하나를 선택합니다.
+ **옵션 A - Greengrass nucleus 런타임**: Greengrass nucleus를 선택한 [V2에서 V1 애플리케이션을 테스트할 새 디바이스 설정](set-up-v2-test-device.md) 경우를 따릅니다. 이 옵션을 사용하면 코드 변경을 최소화하면서 Lambda 함수를 Lambda 구성 요소로 가져올 수 있으며 로컬 섀도우 서비스, 클라이언트 디바이스 및 커넥터와 같은 V1 기능을 지원합니다.
+ **옵션 B - Greengrass nucleus lite 런타임**: Greengrass nucleus lite를 선택한 [V2에서 V1 애플리케이션을 테스트하도록 새 디바이스 설정(Greengrass nucleus lite)](set-up-v2-test-device-lite.md) 경우를 따릅니다. 이 옵션을 사용하려면 AWS IoT Device SDK V2 또는 구성 요소 SDK를 사용하여 Lambda 함수를 일반 AWS IoT Greengrass 구성 요소로 변환해야 하지만 리소스가 제한된 디바이스에 최적화되어 있습니다.

# V2에서 V1 애플리케이션을 테스트할 새 디바이스 설정
<a name="set-up-v2-test-device"></a>

 AWS IoT Greengrass V1 애플리케이션에 대한 구성 AWS요소 및 함수를 배포하고 AWS Lambda 테스트하도록 새 AWS IoT Greengrass V2 코어 디바이스를 설정합니다. 또한 이 V2 코어 디바이스를 사용하여 코어 디바이스에서 네이티브 프로세스를 실행하는 추가 사용자 지정 Greengrass 구성 요소를 개발하고 테스트할 수 있습니다. V2 코어 디바이스에서 애플리케이션을 테스트한 후 기존 V1 코어 디바이스를 V2로 업그레이드하고 V1 기능을 제공하는 V2 구성 요소를 배포할 수 있습니다.



## 1단계: 새 디바이스 AWS IoT Greengrass V2 에 설치
<a name="install-v2-test-device"></a>

새 디바이스에 AWS IoT Greengrass 코어 소프트웨어 v2.x를 설치합니다. [시작하기 자습서](getting-started.md)에 따라 디바이스를 설정하고 구성 요소를 개발하고 배포하는 방법을 알아볼 수 있습니다. 이 자습서에서는 [자동 프로비저닝](quick-installation.md)을 사용하여 디바이스를 빠르게 설정합니다. AWS IoT Greengrass 코어 소프트웨어 v2.x를 설치할 때 디바이스에서 직접 구성 요소를 개발, 테스트 및 디버깅할 수 있도록 [Greengrass CLI](greengrass-cli-component.md)를 배포할 `--deploy-dev-tools` 인수를 지정합니다. 프록시 뒤에 AWS IoT Greengrass 코어 소프트웨어를 설치하거나 하드웨어 보안 모듈(HSM)을 사용하는 방법을 포함하여 다른 설치 옵션에 대한 자세한 내용은 섹션을 참조하세요[AWS IoT Greengrass 코어 소프트웨어 설치](install-greengrass-core-v2.md).

### (선택 사항) Amazon CloudWatch Logs에 로깅 활성화
<a name="enable-cloudwatch-logging-v2"></a>

V2 코어 디바이스에서 Amazon CloudWatch Logs에 로그를 업로드할 수 있도록 하려면 AWS제공 [로그 관리자 구성 요소](log-manager-component.md)를 배포하면 됩니다. CloudWatch Logs를 사용하여 구성 요소 로그를 볼 수 있으므로 코어 디바이스의 파일 시스템에 액세스하지 않고도 디버깅하고 문제를 해결할 수 있습니다. 자세한 내용은 [AWS IoT Greengrass 로그 모니터링](monitor-logs.md) 단원을 참조하십시오.

## 2단계: AWS IoT Greengrass V1 애플리케이션 마이그레이션을 위한 AWS IoT Greengrass V2 구성 요소 생성 및 배포
<a name="run-v1-applications"></a>

대부분의 AWS IoT Greengrass V1 애플리케이션은에서 실행할 수 있습니다 AWS IoT Greengrass V2. Lambda 함수를에서 실행되는 구성 요소로 가져올 수 있으며 AWS IoT Greengrass 커넥터 AWS IoT Greengrass V2와 동일한 기능을 제공하는 [AWS제공 구성 요소를](public-components.md) 사용할 수 있습니다.

또한 사용자 지정 구성 요소를 개발하여 Greengrass 코어 디바이스에서 실행할 기능이나 런타임을 빌드할 수도 있습니다. 로컬에서 구성 요소를 개발하고 테스트하는 방법에 대한 자세한 내용은 [AWS IoT Greengrass 구성 요소 생성](create-components.md) 섹션을 참조하세요.

**Topics**
+ [V1 Lambda 함수 가져오기](#run-v1-lambda-functions)
+ [V1 커넥터 사용](#use-v1-connectors)
+ [Docker 컨테이너 실행](#run-v1-docker-containers)
+ [V1 Greengrass 디바이스 연결](#connect-v1-greengrass-devices)
+ [로컬 섀도 서비스 활성화](#enable-shadow-service)
+ [와 통합 AWS IoT SiteWise](#integrate-with-iot-sitewise)

### V1 Lambda 함수 가져오기
<a name="run-v1-lambda-functions"></a>

Lambda 함수를 AWS IoT Greengrass V2 구성 요소로 가져올 수 있습니다. 다음 접근 방식 중에서 선택합니다.
+ V1 Lambda 함수를 Greengrass 구성 요소로 직접 가져옵니다.
+  AWS IoT Device SDK v2에서 Greengrass 라이브러리를 사용하도록 Lambda 함수를 업데이트한 다음 Lambda 함수를 Greengrass 구성 요소로 가져옵니다.
+ Lambda가 아닌 코드와 AWS IoT Device SDK v2를 사용하여 Lambda 함수와 동일한 기능을 구현하는 사용자 지정 구성 요소를 생성합니다.

Lambda 함수가 스트림 관리자 또는 로컬 보안 암호와 같은 기능을 사용하는 경우 이러한 기능을 패키징하는 AWS제공 구성 요소에 대한 종속성을 정의해야 합니다. Lambda 함수 구성 요소를 배포하는 경우 배포는 종속성으로 정의한 각 기능의 구성 요소도 포함합니다. 배포에서 코어 디바이스에 배포할 보안 암호와 같은 파라미터를 구성할 수 있습니다. 모든 V1 기능에 V2의 Lambda 함수에 대한 구성 요소 종속성이 필요한 것은 아닙니다. 다음 목록은 V2 Lambda 함수 구성 요소에서 V1 기능을 사용하는 방법을 설명합니다. V2 
+ **다른 AWS 서비스에 액세스**

  Lambda 함수가 자격 AWS 증명을 사용하여 다른 AWS 서비스에 요청하는 경우 코어 디바이스의 토큰 교환 역할은 코어 디바이스가 Lambda 함수가 사용하는 AWS 작업을 수행하도록 허용해야 합니다. 자세한 내용은 [코어 디바이스가 AWS 서비스와 상호 작용할 수 있도록 권한 부여](device-service-role.md) 단원을 참조하십시오.
+ **스트림 관리자**

  Lambda 함수가 스트림 관리자를 사용하는 경우 함수를 가져올 때 `aws.greengrass.StreamManager`를 구성 요소 종속성으로 지정합니다. 스트림 관리자 구성 요소를 배포하는 경우 대상 코어 디바이스에 설정할 스트림 관리자 파라미터를 지정합니다. 코어 디바이스의 토큰 교환 역할은 코어 디바이스가 스트림 관리자와 함께 사용하는 AWS 클라우드 대상에 액세스할 수 있도록 허용해야 합니다. 자세한 내용은 [스트림 관리자](stream-manager-component.md) 단원을 참조하십시오.
+ **로컬 보안 암호**

  Lambda 함수가 로컬 보안 암호를 사용하는 경우 함수를 가져올 때 `aws.greengrass.SecretManager`를 구성 요소 종속성으로 지정합니다. 보안 암호 관리자 구성 요소를 배포하는 경우 대상 코어 디바이스에 배포할 보안 암호 리소스를 지정합니다. 코어 디바이스의 토큰 교환 역할은 코어 디바이스가 배포할 보안 암호 리소스를 검색하도록 허용해야 합니다. 자세한 내용은 [보안 암호 관리자](secret-manager-component.md) 단원을 참조하십시오.

  Lambda 함수 구성 요소를 배포할 때 AWS IoT Device SDK V2에서 [GetSecretValue ](ipc-secret-manager.md) [IPC 작업을 사용할 수 있는 권한을 부여하는 IPC 권한 부여 정책을](interprocess-communication.md#ipc-authorization-policies) 갖도록 구성합니다.
+ **로컬 섀도**

  Lambda 함수가 로컬 섀도와 상호 작용하는 경우 AWS IoT Device SDK V2를 사용하도록 Lambda 함수 코드를 업데이트해야 합니다. 함수를 가져오는 경우 `aws.greengrass.ShadowManager`를 구성 요소 종속성으로 지정해야 합니다. 자세한 내용은 [디바이스 섀도와 연동](interact-with-shadows.md) 단원을 참조하십시오.

  Lambda 함수 구성 요소를 배포할 때 AWS IoT Device SDK V2에서 [섀도우](ipc-local-shadows.md) [IPC 작업을 사용할 수 있는 권한을 부여하는 IPC 권한 부여 정책을](interprocess-communication.md#ipc-authorization-policies) 갖도록 구성합니다.
+ **구독**
  + Lambda 함수가 클라우드 소스의 메시지를 구독하는 경우 함수를 가져올 때 해당 구독을 이벤트 소스로 지정합니다.
  + Lambda 함수가 다른 Lambda 함수의 메시지를 구독하거나 Lambda 함수가 AWS IoT Core 또는 다른 Lambda 함수에 메시지를 게시하는 경우 Lambda 함수를 배포할 때 [레거시 구독 라우터 구성 요소를](legacy-subscription-router-component.md) 구성하고 배포합니다. 레거시 구독 라우터 구성 요소를 배포하는 경우 Lambda 함수가 사용하는 구독을 지정합니다.
**참고**  <a name="legacy-subscription-router-requirement-note"></a>
레거시 구독 라우터 구성 요소는 Lambda 함수가 AWS IoT Greengrass 코어 SDK의 `publish()` 함수를 사용하는 경우에만 필요합니다. Lambda 함수 코드를 업데이트하여 AWS IoT Device SDK V2의 프로세스 간 통신(IPC) 인터페이스를 사용하는 경우 레거시 구독 라우터 구성 요소를 배포할 필요가 없습니다. 자세한 내용은 다음 [프로세스 간 통신](interprocess-communication.md) 서비스를 참조하세요.  
[로컬 메시지 게시/구독](ipc-publish-subscribe.md)
[AWS IoT Core MQTT 메시지 게시/구독](ipc-iot-core-mqtt.md)
  + Lambda 함수가 로컬 연결 디바이스의 메시지를 구독하는 경우 함수를 가져올 때 해당 구독을 이벤트 소스로 지정합니다. 또한 [MQTT 브리지 구성 요소](mqtt-bridge-component.md)를 구성하고 배포하여 연결 디바이스의 메시지를 이벤트 소스로 지정한 로컬 게시/구독 주제로 전달해야 합니다.
  + Lambda 함수가 로컬에 연결된 디바이스에 메시지를 게시하는 경우 AWS IoT Device SDK V2를 사용하여 [로컬 게시/구독 메시지를 게시](ipc-publish-subscribe.md)하도록 Lambda 함수 코드를 업데이트해야 합니다. 또한 [로컬 게시/구독 메시지 브로커에서 연결 디바이스로 메시지를 전달하기 위해 MQTT 브리지 구성 요소](mqtt-bridge-component.md)를 구성하고 배포해야 합니다.
+ **로컬 볼륨 및 디바이스**

  컨테이너화된 Lambda 함수가 로컬 볼륨 또는 디바이스에 액세스하는 경우 Lambda 함수를 가져올 때 해당 볼륨과 디바이스를 지정합니다. 이 기능에는 구성 요소 종속성이 필요하지 않습니다.

자세한 내용은 [AWS Lambda 함수 실행](run-lambda-functions.md) 단원을 참조하십시오.

### V1 커넥터 사용
<a name="use-v1-connectors"></a>

일부 AWS IoT Greengrass 커넥터와 동일한 기능을 제공하는 AWS구성 요소를 배포할 수 있습니다. 배포를 생성하는 경우 커넥터의 파라미터를 구성할 수 있습니다.

다음 AWS IoT Greengrass V2 구성 요소는 Greengrass V1 커넥터 기능을 제공합니다.
+ [CloudWatch 지표 구성 요소](cloudwatch-metrics-component.md)
+ [AWS IoT Device Defender component](device-defender-component.md)
+ [Firehose 구성 요소](kinesis-firehose-component.md)
+ [Modbus-RTU 프로토콜 어댑터 구성 요소](modbus-rtu-protocol-adapter-component.md)
+ [Amazon SNS 구성 요소](sns-component.md)

### Docker 컨테이너 실행
<a name="run-v1-docker-containers"></a>

AWS IoT Greengrass V2 는 V1 Docker 애플리케이션 배포 커넥터를 직접 대체하는 구성 요소를 제공하지 않습니다. 그러나 Docker 애플리케이션 관리자 구성 요소를 사용하여 Docker 이미지를 다운로드한 다음 다운로드한 이미지에서 Docker 컨테이너를 실행하는 사용자 지정 구성 요소를 생성할 수 있습니다. 자세한 내용은 [Docker 컨테이너 실행](run-docker-container.md) 및 [Docker 애플리케이션 관리자](docker-application-manager-component.md) 섹션을 참조하세요.

### V1 Greengrass 디바이스 연결
<a name="connect-v1-greengrass-devices"></a>

의 연결된 디바이스 AWS IoT Greengrass V1 를의 클라이언트 디바이스라고 합니다 AWS IoT Greengrass V2. 클라이언트 디바이스에 대한 AWS IoT Greengrass V2 지원은 이전 버전과 호환 AWS IoT Greengrass V1되므로 애플리케이션 코드를 변경하지 않고도 V1 클라이언트 디바이스를 V2 코어 디바이스에 연결할 수 있습니다. 클라이언트 디바이스가 V2 코어 디바이스에 연결할 수 있도록 하려면 클라이언트 디바이스 지원을 지원하는 Greengrass 구성 요소를 배포하고 클라이언트 디바이스를 코어 디바이스에 연결합니다. 클라이언트 디바이스, AWS IoT Core 클라우드 서비스, Greengrass 구성 요소(Lambda 함수 포함) 간 메시지를 전달하려면 [MQTT 브리지 구성 요소](mqtt-bridge-component.md)를 배포하고 구성합니다. [IP 감지기 구성 요소](ip-detector-component.md)를 배포하여 연결 정보를 자동으로 감지하거나 엔드포인트를 수동으로 관리할 수 있습니다. 자세한 내용은 [로컬 IoT 디바이스와 상호 작용](interact-with-local-iot-devices.md) 단원을 참조하십시오.

### 로컬 섀도 서비스 활성화
<a name="enable-shadow-service"></a>

에서 AWS IoT Greengrass V2로컬 섀도 서비스는 AWS제공 섀도 관리자 구성 요소에 의해 구현됩니다. 에는 명명된 섀도에 대한 지원 AWS IoT Greengrass V2 도 포함됩니다. 구성 요소가 로컬 섀도와 상호 작용하고 섀도 상태를에 동기화하도록 하려면 섀도 관리자 구성 요소를 AWS IoT Core구성 및 배포하고 구성 요소 코드에서 섀도 IPC 작업을 사용합니다. 자세한 내용은 [디바이스 섀도와 연동](interact-with-shadows.md) 단원을 참조하십시오.

### 와 통합 AWS IoT SiteWise
<a name="integrate-with-iot-sitewise"></a>

V1 코어 디바이스를 AWS IoT SiteWise 게이트웨이로 사용하는 경우 [지침에 따라](https://docs.aws.amazon.com/iot-sitewise/latest/userguide/configure-gateway-ggv2.html) 새 V2 코어 디바이스를 AWS IoT SiteWise 게이트웨이로 설정합니다. AWS IoT SiteWise 는 AWS IoT SiteWise 구성 요소를 배포하는 설치 스크립트를 제공합니다.

## 3단계: AWS IoT Greengrass V2 애플리케이션 테스트
<a name="test-v2-features"></a>

새로운 V2 코어 디바이스에 V2 구성 요소를 생성하고 배포한 후에는 애플리케이션이 기대치를 충족하는지 확인합니다. 디바이스의 로그를 확인하여 구성 요소의 표준 출력(stdout) 및 표준 오류(stderr) 메시지를 볼 수 있습니다. 자세한 내용은 [AWS IoT Greengrass 로그 모니터링](monitor-logs.md) 단원을 참조하십시오.

[Greengrass CLI](greengrass-cli-component.md)를 코어 디바이스에 배포한 경우 이를 사용하여 구성 요소 및 해당 구성을 디버깅할 수 있습니다. 자세한 내용은 [Greengrass CLI 명령](gg-cli-reference.md) 단원을 참조하십시오.

애플리케이션이 V2 코어 디바이스에서 작동하는지 확인한 후에는 애플리케이션의 Greengrass 구성 요소를 다른 코어 디바이스에 배포할 수 있습니다. 네이티브 프로세스 또는 Docker 컨테이너를 실행하는 사용자 지정 구성 요소를 개발한 경우 먼저 [해당 구성 요소를 서비스에 게시](publish-components.md)하여 다른 코어 디바이스에 배포해야 합니다. AWS IoT Greengrass 

# V2에서 V1 애플리케이션을 테스트하도록 새 디바이스 설정(Greengrass nucleus lite)
<a name="set-up-v2-test-device-lite"></a>

Greengrass nucleus lite로 새 디바이스를 설정하여 AWS IoT Greengrass V1 애플리케이션을 V2로 마이그레이션하기 위해 생성한 일반 구성 요소를 테스트합니다. Greengrass nucleus lite는 리소스가 제한된 디바이스에 최적화된 경량 런타임입니다. 이 디바이스를 사용하여 네이티브 프로세스를 실행하는 사용자 지정 Greengrass 구성 요소를 개발하고 테스트할 수 있습니다. Greengrass nucleus lite 디바이스에서 애플리케이션을 테스트한 후 Greengrass nucleus lite를 실행하는 다른 디바이스에 V2 구성 요소를 배포하거나 기존 V1 코어 디바이스를 V2로 업그레이드할 수 있습니다.



## 1단계: 새 디바이스에 Greengrass nucleus lite 설치
<a name="lite-step-1-install"></a>

새 디바이스에 Greengrass nucleus lite를 설치합니다. [Greengrass nucleus lite 설치 가이드](https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-nucleus-lite-component.html#greengrass-nucleus-lite-component-install)에 따라 디바이스를 설정합니다.

**참고**  
Greengrass nucleus lite는 현재 로컬 섀도우 서비스, 클라이언트 디바이스 또는 커넥터를 지원하지 않습니다. 이 가이드를 진행하기 전에 V1 애플리케이션이 이러한 기능에 의존하지 않는지 확인하세요.

## 2단계: AWS IoT Greengrass V1 Lambda 함수를 마이그레이션하기 위한 일반 구성 요소 생성 및 배포
<a name="lite-step-2-convert-lambda"></a>

Greengrass nucleus lite에서 AWS IoT Greengrass V1 Lambda 함수의 기능을 복제하려면 함수를 일반 구성 요소로 변환해야 합니다. 여기에는 AWS IoT Greengrass 코어 SDK 대신 AWS IoT Device SDK V2 또는 AWS IoT Greengrass 구성 요소 SDK를 사용하도록 Lambda 함수 코드를 다시 작성하는 작업이 포함됩니다.

다음 표에는이 설명서의 V2 구성 요소 예제에 사용된 SDKs가 나열되어 있습니다.


| SDK | 최소 버전 | 
| --- | --- | 
| [AWS IoT Device SDK Python v2용](https://github.com/aws/aws-iot-device-sdk-python-v2) | v1.11.3 | 
| [AWS IoT Device SDK Java v2용](https://github.com/aws/aws-iot-device-sdk-java-v2) | v1.9.3 | 
| [AWS IoT Device SDK JavaScript v2용](https://github.com/aws/aws-iot-device-sdk-js-v2) | v1.12.0 | 
| [AWS IoT Greengrass 구성 요소 SDK(C/C\$1\$1)](https://github.com/aws-greengrass/aws-greengrass-component-sdk)(현재 미리 보기 중) | v0.4.0 | 

아래 예제는 두 가지 주요 시나리오에 대해 여러 프로그래밍 언어로 구성 요소 코드, 레시피 및 빌드 지침과 함께 AWS IoT Greengrass V1 코어 SDK 및 이에 상응하는 일반 구성 요소를 사용하는 Lambda 함수를 보여줍니다.
+ **로컬 통신** - 로컬 pub/sub를 사용하여 동일한 디바이스의 다른 구성 요소와 통신하는 구성 요소
+ **클라우드 통신** - AWS IoT Core 또는 기타 AWS 서비스와 통신하는 구성 요소

### 시나리오 1: 로컬 통신(게시자 → 프로세서 → 구독자)
<a name="lite-example-local-communication"></a>

이 시나리오에서는 로컬 pub/sub 통신을 사용하는 V1 Lambda 함수를 V2 일반 구성 요소로 변환하는 방법을 보여줍니다.

#### 애플리케이션 아키텍처
<a name="lite-example-1-scenario"></a>

이 예제에는 세 가지 구성 요소가 포함되어 있습니다.
+ 게시자 Lambda가 온도 데이터 게시
+ 프로세서 Lambda는 데이터를 수신하고 처리합니다.
+ 프로세서 Lambda가 처리된 결과를 구독자 Lambda에 게시

아래 코드 예제는 로컬 통신을 위한 메시지 구독 및 게시를 모두 보여주는 프로세서 Lambda에 중점을 둡니다.

##### V1 그룹 구독
<a name="lite-example-1-v1-subscriptions"></a>

에서 AWS IoT Greengrass V1다음 그룹 구독은 Lambda 함수 간의 통신을 활성화합니다.

구독 1: 게시자 → 프로세서
+ 소스: Lambda(게시자)
+ 대상: Lambda(프로세서)
+ 주제: 센서/온도

구독 2: 프로세서 → 구독자
+ 소스: Lambda(프로세서)
+ 대상: Lambda(구독자)
+ 주제: lambda/alerts

#### 프로세서 Lambda 함수(V1)
<a name="lite-example-1-v1-code"></a>

------
#### [ Python ]

```
import greengrasssdk
import json

iot_client = greengrasssdk.client('iot-data')

def lambda_handler(event, context):
    """
    Receives temperature from publisher Lambda,
    processes it, and forwards to subscriber Lambda
    """
    # Receive from publisher Lambda.
    sensor_id = event['sensor_id']
    temperature = event['temperature']
    
    print(f"Received from sensor {sensor_id}: {temperature}°F")
    
    # Process: Check if temperature is high.
    if temperature > 80:
        alert_data = {
            'sensor_id': sensor_id,
            'temperature': temperature,
            'alert': 'HIGH_TEMPERATURE'
        }
        
        # Publish to another Lambda using greengrasssdk.
        iot_client.publish(
            topic='lambda/alerts',
            payload=json.dumps(alert_data)
        )
        
        print(f"Alert sent to subscriber Lambda")
    
    return {'statusCode': 200}
```

------
#### [ Java ]

```
import com.amazonaws.greengrass.javasdk.IotDataClient;
import com.amazonaws.greengrass.javasdk.model.PublishRequest;
import com.amazonaws.services.lambda.runtime.Context;
import com.google.gson.Gson;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class TemperatureProcessorLambda {
    private static final Gson gson = new Gson();
    private final IotDataClient iotDataClient;

    public TemperatureProcessorLambda() {
        this.iotDataClient = new IotDataClient();
    }

    public String handleRequest(Map<String, Object> event, Context context) {
        /*
         * Receives temperature from publisher Lambda,
         * processes it, and forwards to subscriber Lambda
         */

        // Receive from publisher Lambda.
        String sensorId = (String) event.get("sensor_id");
        Number temp = (Number) event.get("temperature");
        int temperature = temp.intValue();

        System.out.println("Received from sensor " + sensorId + ": " + temperature + "°F");

        // Process: Check if temperature is high.
        if (temperature > 80) {
            Map<String, Object> alertData = new HashMap<>();
            alertData.put("sensor_id", sensorId);
            alertData.put("temperature", temperature);
            alertData.put("alert", "HIGH_TEMPERATURE");

            // Publish to another Lambda using greengrasssdk.
            String payload = gson.toJson(alertData);
            PublishRequest publishRequest = new PublishRequest()
                .withTopic("lambda/alerts")
                .withPayload(ByteBuffer.wrap(payload.getBytes(StandardCharsets.UTF_8)));

            iotDataClient.publish(publishRequest);

            System.out.println("Alert sent to subscriber Lambda");
        }

        return "Success";
    }
}
```

------
#### [ JavaScript ]

```
const greengrasssdk = require('aws-greengrass-core-sdk');

const iotClient = new greengrasssdk.IotData();

/**
 * Greengrass v1 Lambda function
 * Receives temperature from publisher Lambda,
 * processes it, and forwards to subscriber Lambda
 */
exports.handler = function(event, context) {
    // Receive from publisher Lambda.
    const sensorId = event.sensor_id;
    const temperature = event.temperature;
    
    console.log(`Received from sensor ${sensorId}: ${temperature}°F`);
    
    // Process: Check if temperature is high.
    if (temperature > 80) {
        const alertData = {
            sensor_id: sensorId,
            temperature: temperature,
            alert: 'HIGH_TEMPERATURE'
        };
        
        // Publish to another Lambda using greengrasssdk.
        const params = {
            topic: 'lambda/alerts',
            payload: JSON.stringify(alertData)
        };
        
        iotClient.publish(params, (err) => {
            if (err) {
                console.error('Error publishing alert:', err);
                context.fail(err);
            } else {
                console.log('Alert sent to subscriber Lambda');
                context.succeed('Success');
            }
        });
    } else {
        context.succeed('Success');
    }
};
```

------
#### [ C ]

```
#include <aws/greengrass/greengrasssdk.h>
#include <stdio.h>
#include <string.h>
#include <jansson.h>  // For JSON parsing.

static aws_greengrass_iot_data_client *iot_client = NULL;

void on_message_received(const char *topic, const uint8_t *payload, size_t payload_len, void *user_data) {
    // Parse the incoming message.
    char *payload_str = strndup((char *)payload, payload_len);
    json_error_t error;
    json_t *event = json_loads(payload_str, 0, &error);
    free(payload_str);
    
    if (!event) {
        fprintf(stderr, "Error parsing JSON: %s\n", error.text);
        return;
    }
    
    // Receive from publisher Lambda.
    json_t *sensor_id_obj = json_object_get(event, "sensor_id");
    json_t *temperature_obj = json_object_get(event, "temperature");
    
    const char *sensor_id = json_string_value(sensor_id_obj);
    int temperature = json_integer_value(temperature_obj);
    
    printf("Received from sensor %s: %d°F\n", sensor_id, temperature);
    
    // Process: Check if temperature is high.
    if (temperature > 80) {
        // Create alert data.
        json_t *alert_data = json_object();
        json_object_set_new(alert_data, "sensor_id", json_string(sensor_id));
        json_object_set_new(alert_data, "temperature", json_integer(temperature));
        json_object_set_new(alert_data, "alert", json_string("HIGH_TEMPERATURE"));
        
        // Convert to JSON string.
        char *alert_payload = json_dumps(alert_data, JSON_COMPACT);
        
        // Publish to another Lambda using greengrasssdk.
        aws_greengrass_publish_params params = {
            .topic = "lambda/alerts",
            .payload = (uint8_t *)alert_payload,
            .payload_len = strlen(alert_payload)
        };
        
        aws_greengrass_iot_data_publish(iot_client, &params);
        
        printf("Alert sent to subscriber Lambda\n");
        
        free(alert_payload);
        json_decref(alert_data);
    }
    
    json_decref(event);
}

int main(int argc, char *argv[]) {
    // Initialize Greengrass SDK.
    iot_client = aws_greengrass_iot_data_client_new();
    
    // Subscribe to temperature sensor topic.
    aws_greengrass_subscribe_params subscribe_params = {
        .topic = "sensors/temperature",
        .callback = on_message_received,
        .user_data = NULL
    };
    
    aws_greengrass_iot_data_subscribe(iot_client, &subscribe_params);
    
    printf("Temperature Processor Lambda started\n");
    printf("Subscribed to sensors/temperature\n");
    printf("Waiting for sensor data...\n");
    
    // Keep the Lambda running.
    while (1) {
        sleep(1);
    }
    
    return 0;
}
```

------
#### [ C\$1\$1 ]

```
#include <aws/greengrass/greengrasssdk.h>
#include <iostream>
#include <string>
#include <memory>
#include <jansson.h> // For JSON parsing.
#include <unistd.h>

class TemperatureProcessor {
private:
    std::unique_ptr<aws_greengrass_iot_data_client, 
                    decltype(&aws_greengrass_iot_data_client_destroy)> iot_client;
    
    static void message_callback_wrapper(const char *topic, 
                                        const uint8_t *payload, 
                                        size_t payload_len, 
                                        void *user_data) {
        auto* processor = static_cast<TemperatureProcessor*>(user_data);
        processor->on_message_received(topic, payload, payload_len);
    }

public:
    TemperatureProcessor() 
        : iot_client(aws_greengrass_iot_data_client_new(), 
                     aws_greengrass_iot_data_client_destroy) {
        if (!iot_client) {
            throw std::runtime_error("Failed to create Greengrass IoT client");
        }
    }

    void on_message_received(const char *topic, 
                            const uint8_t *payload, 
                            size_t payload_len) {
        // Parse the incoming message.
        std::string payload_str(reinterpret_cast<const char*>(payload), payload_len);
        
        json_error_t error;
        json_t *event = json_loads(payload_str.c_str(), 0, &error);
        
        if (!event) {
            std::cerr << "Error parsing JSON: " << error.text << std::endl;
            return;
        }

        json_t *sensor_id_obj = json_object_get(event, "sensor_id");
        json_t *temperature_obj = json_object_get(event, "temperature");
        
        const char *sensor_id = json_string_value(sensor_id_obj);
        int temperature = json_integer_value(temperature_obj);
        
        std::cout << "Received from sensor " << sensor_id 
                  << ": " << temperature << "°F" << std::endl;

        if (temperature > 80) {
            send_alert(sensor_id, temperature);
        }

        json_decref(event);
    }

    void send_alert(const char *sensor_id, int temperature) {
        // Create alert data.
        json_t *alert_data = json_object();
        json_object_set_new(alert_data, "sensor_id", json_string(sensor_id));
        json_object_set_new(alert_data, "temperature", json_integer(temperature));
        json_object_set_new(alert_data, "alert", json_string("HIGH_TEMPERATURE"));

        // Convert to JSON string.
        char *alert_payload = json_dumps(alert_data, JSON_COMPACT);

        // Publish to another Lambda using greengrasssdk.
        aws_greengrass_publish_params params = {
            .topic = "lambda/alerts",
            .payload = reinterpret_cast<uint8_t*>(alert_payload),
            .payload_len = strlen(alert_payload)
        };
        
        aws_greengrass_iot_data_publish(iot_client.get(), &params);
        
        std::cout << "Alert sent to subscriber Lambda" << std::endl;

        free(alert_payload);
        json_decref(alert_data);
    }

    void subscribe_to_topic(const std::string& topic) {
        aws_greengrass_subscribe_params subscribe_params = {
            .topic = topic.c_str(),
            .callback = message_callback_wrapper,
            .user_data = this
        };
        
        aws_greengrass_iot_data_subscribe(iot_client.get(), &subscribe_params);
        
        std::cout << "Temperature Processor Lambda started" << std::endl;
        std::cout << "Subscribed to " << topic << std::endl;
        std::cout << "Waiting for sensor data..." << std::endl;
    }

    void run() {
        // Keep the Lambda running.
        while (true) {
            sleep(1);
        }
    }
};

int main(int argc, char *argv[]) {
    try {
        TemperatureProcessor processor;
        processor.subscribe_to_topic("sensors/temperature");
        processor.run();
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    
    return 0;
}
```

------

#### 일반 구성 요소(V2)
<a name="lite-example-1-v2-code"></a>

에서 동일한 기능을 구현하려면 다음을 사용하여 일반 구성 요소를 AWS IoT Greengrass V2생성합니다.

##### 1. 구성 요소 코드
<a name="lite-example-1-component-code"></a>

------
#### [ Python ]

사전 조건:이 구성 요소 코드를 사용하기 전에 Greengrass 디바이스에 Python AWS IoT Device SDK 용를 설치하고 확인합니다.

```
# Install the SDK
pip3 install awsiotsdk

# Verify installation
python3 -c "import awsiot.greengrasscoreipc.clientv2; print('SDK installed successfully')"
```

설치 중에 종속성 충돌이 발생하는 경우 특정 버전의를 설치해 보십시오 AWS IoT Device SDK.

확인 명령이 "SDK installed successfully"를 인쇄하면 구성 요소 코드를 사용할 준비가 된 것입니다.

```
from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
from awsiot.greengrasscoreipc.model import (
    PublishMessage,
    JsonMessage
)
import time

ipc_client = GreengrassCoreIPCClientV2()

def on_sensor_data(event):
    """
    Receives temperature from sensor publisher component,
    processes it, and forwards to alert component
    """
    try:
        # Receive from publisher component.
        data = event.json_message.message
        sensor_id = data['sensor_id']
        temperature = data['temperature']
        
        print(f"Received from sensor {sensor_id}: {temperature}°F")
        
        # Process: Check if temperature is high.
        if temperature > 80:
            alert_data = {
                'sensor_id': sensor_id,
                'temperature': temperature,
                'alert': 'HIGH_TEMPERATURE'
            }
            
            # Publish to another component (AlertHandler).
            ipc_client.publish_to_topic(
                topic='component/alerts',
                publish_message=PublishMessage(
                    json_message=JsonMessage(message=alert_data)
                )
            )
            
            print(f"Alert sent to AlertHandler component")
    
    except Exception as e:
        print(f"Error processing sensor data: {e}")

def main():
    print("Temperature Processor component starting...")
    
    # Subscribe to sensor data from publisher component.
    ipc_client.subscribe_to_topic(
        topic='sensors/temperature',
        on_stream_event=on_sensor_data
    )
    
    print("Subscribed to sensors/temperature")
    print("Waiting for sensor data...")
    
    # Keep running.
    while True:
        time.sleep(1)

if __name__ == '__main__':
    main()
```

------
#### [ Java ]

```
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClientV2;
import software.amazon.awssdk.aws.greengrass.model.PublishMessage;
import software.amazon.awssdk.aws.greengrass.model.PublishToTopicRequest;
import software.amazon.awssdk.aws.greengrass.model.JsonMessage;
import software.amazon.awssdk.aws.greengrass.model.SubscribeToTopicRequest;
import software.amazon.awssdk.aws.greengrass.model.SubscriptionResponseMessage;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class TemperatureProcessor {
    private static GreengrassCoreIPCClientV2 ipcClient;

    public static void main(String[] args) {
        System.out.println("Temperature Processor component starting...");

        try (GreengrassCoreIPCClientV2 client = GreengrassCoreIPCClientV2.builder().build()) {
            ipcClient = client;

            SubscribeToTopicRequest subscribeRequest = new SubscribeToTopicRequest()
                .withTopic("sensors/temperature");

            ipcClient.subscribeToTopic(
                subscribeRequest, 
                TemperatureProcessor::onSensorData,
                Optional.empty(),
                Optional.empty()
            );

            System.out.println("Subscribed to sensors/temperature");
            System.out.println("Waiting for sensor data...");

            while (true) {
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void onSensorData(SubscriptionResponseMessage message) {
        try {
            Map<String, Object> data = message.getJsonMessage().getMessage();
            String sensorId = (String) data.get("sensor_id");
            Number temp = (Number) data.get("temperature");
            int temperature = temp.intValue();

            System.out.println("Received from sensor " + sensorId + ": " + temperature + "F");

            if (temperature > 80) {
                Map<String, Object> alertData = new HashMap<>();
                alertData.put("sensor_id", sensorId);
                alertData.put("temperature", temperature);
                alertData.put("alert", "HIGH_TEMPERATURE");

                JsonMessage jsonMessage = new JsonMessage().withMessage(alertData);
                PublishMessage publishMessage = new PublishMessage().withJsonMessage(jsonMessage);
                PublishToTopicRequest publishRequest = new PublishToTopicRequest()
                    .withTopic("component/alerts")
                    .withPublishMessage(publishMessage);

                ipcClient.publishToTopic(publishRequest);
                System.out.println("Alert sent to AlertHandler component");
            }
        } catch (Exception e) {
            System.err.println("Error processing sensor data: " + e.getMessage());
        }
    }
}
```

------
#### [ JavaScript ]

```
const greengrasscoreipc = require('aws-iot-device-sdk-v2').greengrasscoreipc;

class TemperatureProcessor {
    constructor() {
        this.ipcClient = null;
    }

    async start() {
        console.log('Temperature Processor component starting...');
        
        try {
            this.ipcClient = greengrasscoreipc.createClient();
            await this.ipcClient.connect();
            
            const subscribeRequest = {
                topic: 'sensors/temperature'
            };

            const streamingOperation = this.ipcClient.subscribeToTopic(subscribeRequest);
            
            streamingOperation.on('message', (message) => {
                this.onSensorData(message);
            });
            
            streamingOperation.on('streamError', (error) => {
                console.error('Stream error:', error);
            });
            
            streamingOperation.on('ended', () => {
                console.log('Subscription stream ended');
            });
            
            await streamingOperation.activate();
            
            console.log('Subscribed to sensors/temperature');
            console.log('Waiting for sensor data...');
            
        } catch (error) {
            console.error('Error starting component:', error);
            process.exit(1);
        }
    }

    async onSensorData(message) {
        try {
            const data = message.jsonMessage.message;
            
            const sensorId = data.sensor_id;
            const temperature = data.temperature;
            
            console.log(`Received from sensor ${sensorId}: ${temperature}°F`);
            
            if (temperature > 80) {
                const alertData = {
                    sensor_id: sensorId,
                    temperature: temperature,
                    alert: 'HIGH_TEMPERATURE'
                };
                
                const publishRequest = {
                    topic: 'component/alerts',
                    publishMessage: {
                        jsonMessage: {
                            message: alertData
                        }
                    }
                };
                
                await this.ipcClient.publishToTopic(publishRequest);
                console.log('Alert sent to AlertHandler component');
            }
            
        } catch (error) {
            console.error('Error processing sensor data:', error);
        }
    }
}

// Start the component.
const processor = new TemperatureProcessor();
processor.start();
```

------
#### [ C ]

```
#include <gg/buffer.h>
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/map.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

#define SUBSCRIBE_TOPIC "sensors/temperature"
#define PUBLISH_TOPIC "component/alerts"

typedef struct {
    char sensor_id[64];
    int64_t temperature;
} AlertData;

static pthread_mutex_t alert_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t alert_cond = PTHREAD_COND_INITIALIZER;
static AlertData pending_alert;
static bool has_pending_alert = false;

static void *alert_publisher_thread(void *arg) {
    (void) arg;
    
    while (true) {
        pthread_mutex_lock(&alert_mutex);
        while (!has_pending_alert) {
            pthread_cond_wait(&alert_cond, &alert_mutex);
        }
        
        AlertData alert = pending_alert;
        has_pending_alert = false;
        pthread_mutex_unlock(&alert_mutex);
        
        GgBuffer sensor_id_buf = { .data = (uint8_t *)alert.sensor_id, .len = strlen(alert.sensor_id) };
        GgMap payload = GG_MAP(
            gg_kv(GG_STR("sensor_id"), gg_obj_buf(sensor_id_buf)),
            gg_kv(GG_STR("temperature"), gg_obj_i64(alert.temperature)),
            gg_kv(GG_STR("alert"), gg_obj_buf(GG_STR("HIGH_TEMPERATURE")))
        );
        
        GgError ret = ggipc_publish_to_topic_json(GG_STR(PUBLISH_TOPIC), payload);
        
        if (ret != GG_ERR_OK) {
            fprintf(stderr, "Failed to publish alert\n");
        } else {
            printf("Alert sent to AlertHandler component\n");
        }
    }
    
    return NULL;
}

static void on_sensor_data(
    void *ctx, GgBuffer topic, GgObject payload, GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) topic;
    (void) handle;
    
    if (gg_obj_type(payload) != GG_TYPE_MAP) {
        fprintf(stderr, "Expected JSON message\n");
        return;
    }
    
    GgMap map = gg_obj_into_map(payload);
    
    GgObject *sensor_id_obj;
    if (!gg_map_get(map, GG_STR("sensor_id"), &sensor_id_obj)) {
        fprintf(stderr, "Missing sensor_id field\n");
        return;
    }
    GgBuffer sensor_id = gg_obj_into_buf(*sensor_id_obj);
    
    GgObject *temperature_obj;
    if (!gg_map_get(map, GG_STR("temperature"), &temperature_obj)) {
        fprintf(stderr, "Missing temperature field\n");
        return;
    }
    int64_t temperature = gg_obj_into_i64(*temperature_obj);
    
    printf("Received from sensor %.*s: %lld°F\n", 
           (int)sensor_id.len, sensor_id.data, (long long)temperature);
    
    if (temperature > 80) {
        pthread_mutex_lock(&alert_mutex);
        snprintf(pending_alert.sensor_id, sizeof(pending_alert.sensor_id),
                 "%.*s", (int)sensor_id.len, sensor_id.data);
        pending_alert.temperature = temperature;
        has_pending_alert = true;
        pthread_cond_signal(&alert_cond);
        pthread_mutex_unlock(&alert_mutex);
    }
}

int main(void) {
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("Temperature Processor component starting...\n");
    
    gg_sdk_init();
    
    GgError ret = ggipc_connect();
    if (ret != GG_ERR_OK) {
        fprintf(stderr, "Failed to connect to Greengrass nucleus\n");
        exit(1);
    }
    printf("Connected to Greengrass IPC\n");
    
    // Start alert publisher thread.
    pthread_t alert_thread;
    if (pthread_create(&alert_thread, NULL, alert_publisher_thread, NULL) != 0) {
        fprintf(stderr, "Failed to create alert publisher thread\n");
        exit(1);
    }
    
    GgIpcSubscriptionHandle handle;
    ret = ggipc_subscribe_to_topic(
        GG_STR(SUBSCRIBE_TOPIC),
        &on_sensor_data,
        NULL,
        &handle
    );
    
    if (ret != GG_ERR_OK) {
        fprintf(stderr, "Failed to subscribe to topic\n");
        exit(1);
    }
    
    printf("Subscribed to %s\n", SUBSCRIBE_TOPIC);
    printf("Waiting for sensor data...\n");
    
    // Keep running.
    while (true) {
        sleep(1);
    }
    
    return 0;
}
```

------
#### [ C\$1\$1 ]

```
#include <gg/ipc/client.hpp>
#include <gg/buffer.hpp>
#include <gg/object.hpp>
#include <gg/types.hpp>

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <string_view>
#include <thread>

struct AlertData {
    std::string sensor_id;
    int64_t temperature;
};

static std::mutex alert_mutex;
static std::condition_variable alert_cv;
static AlertData pending_alert;
static bool has_pending_alert = false;

void alert_publisher_thread() {
    auto& client = gg::ipc::Client::get();
    
    while (true) {
        std::unique_lock<std::mutex> lock(alert_mutex);
        alert_cv.wait(lock, [] { return has_pending_alert; });
        
        AlertData alert = pending_alert;
        has_pending_alert = false;
        lock.unlock();
        
        // Create alert payload as JSON string.
        std::string json_payload = "{\"sensor_id\":\"" + alert.sensor_id + 
                                  "\",\"temperature\":" + std::to_string(alert.temperature) + 
                                  ",\"alert\":\"HIGH_TEMPERATURE\"}";
        
        // Convert to Buffer and publish.
        gg::Buffer buffer(json_payload);
        auto error = client.publish_to_topic("component/alerts", buffer);
        
        if (error) {
            std::cerr << "Failed to publish alert\n";
        } else {
            std::cout << "Alert sent to AlertHandler component\n";
        }
    }
}

class SensorCallback : public gg::ipc::LocalTopicCallback {
    void operator()(
        std::string_view topic,
        gg::Object payload,
        gg::ipc::Subscription& handle
    ) override {
        (void) topic;
        (void) handle;
        
        // Payload is a Buffer containing JSON string.
        if (payload.index() != GG_TYPE_BUF) {
            std::cerr << "Expected Buffer message\n";
            return;
        }
        
        // Extract buffer using gg::get.
        auto buffer = gg::get<std::span<uint8_t>>(payload);
        std::string json_str(reinterpret_cast<const char*>(buffer.data()), buffer.size());
        
        // Simple JSON parsing for demo.
        std::string sensor_id = "sensor1"; 
        int64_t temperature = 0;
        
        // Extract temperature (simple string search).
        size_t temp_pos = json_str.find("\"temperature\":");
        if (temp_pos != std::string::npos) {
            temp_pos += 14; // Skip "temperature".
            size_t end_pos = json_str.find_first_of(",}", temp_pos);
            if (end_pos != std::string::npos) {
                temperature = std::stoll(json_str.substr(temp_pos, end_pos - temp_pos));
            }
        }
        
        std::cout << "Received from sensor " << sensor_id << ": " 
                  << temperature << "°F\n";
        
        if (temperature > 80) {
            std::lock_guard<std::mutex> lock(alert_mutex);
            pending_alert = {sensor_id, temperature};
            has_pending_alert = true;
            alert_cv.notify_one();
        }
    }
};

int main() {
    // Disable stdout buffering for real-time logging.
    std::cout.setf(std::ios::unitbuf);
    
    std::cout << "Temperature Processor component starting..." << std::endl;
    
    auto& client = gg::ipc::Client::get();
    std::cout << "Got client instance" << std::endl;
    
    auto error = client.connect();
    std::cout << "Connect returned, error code: " << error.value() << std::endl;
    
    if (error) {
        std::cerr << "Failed to connect to Greengrass nucleus: " << error.message() << std::endl;
        return 1;
    }
    
    std::cout << "Connected to Greengrass IPC" << std::endl;
    
    // Start alert publisher thread.
    std::thread alert_thread(alert_publisher_thread);
    alert_thread.detach();
    
    // Handler must be static lifetime if subscription handle is not held.
    static SensorCallback handler;
    error = client.subscribe_to_topic("sensors/temperature", handler);
    
    if (error) {
        std::cerr << "Failed to subscribe to topic: " << error.message() << std::endl;
        return 1;
    }
    
    std::cout << "Subscribed to sensors/temperature" << std::endl;
    std::cout << "Waiting for sensor data..." << std::endl;
    
    // Keep running.
    while (true) {
        using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s);
    }
    
    return 0;
}
```

------

##### 2. 구성 요소 빌드 및 패키징
<a name="lite-example-1-build-component"></a>

일부 언어는 배포 전에 빌드 또는 패키징이 필요합니다.

------
#### [ Python ]

Python은 컴파일이 필요하지 않습니다. 구성 요소는 .py 파일을 직접 사용할 수 있습니다.

------
#### [ Java ]

모든 종속성이 번들로 제공되는 실행 파일 JAR을 빌드하려면:

1. 프로젝트 디렉터리에 `pom.xml` 파일을 생성합니다.

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
   
       <!-- Basic project information: organization, component name, and version -->
       <groupId>com.example</groupId>
       <artifactId>temperature-processor</artifactId>
       <version>1.0.0</version>
   
       <properties>
           <!-- Java 11 LTS (Long Term Support) is recommended for Greengrass v2 components -->
           <maven.compiler.source>11</maven.compiler.source>
           <maven.compiler.target>11</maven.compiler.target>
       </properties>
   
       <dependencies>
           <!-- AWS IoT Device SDK for Java - provides IPC client for Greengrass v2 local communication -->
           <dependency>
               <groupId>software.amazon.awssdk.iotdevicesdk</groupId>
               <artifactId>aws-iot-device-sdk</artifactId>
               <version>1.25.1</version>
           </dependency>
       </dependencies>
   
       <build>
           <plugins>
               <!-- Maven Shade Plugin - creates a standalone JAR with all dependencies included for Greengrass deployment -->
               <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-shade-plugin</artifactId>
                   <version>3.2.4</version>
                   <executions>
                       <execution>
                           <phase>package</phase>
                           <goals>
                               <goal>shade</goal>
                           </goals>
                           <configuration>
                               <transformers>
                                   <!-- Set the main class for the executable JAR -->
                                   <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                       <mainClass>TemperatureProcessor</mainClass>
                                   </transformer>
                               </transformers>
                               <filters>
                                   <!-- Exclude signature files to avoid security exceptions -->
                                   <filter>
                                       <artifact>*:*</artifact>
                                       <excludes>
                                           <exclude>META-INF/*.SF</exclude>
                                           <exclude>META-INF/*.DSA</exclude>
                                           <exclude>META-INF/*.RSA</exclude>
                                       </excludes>
                                   </filter>
                               </filters>
                           </configuration>
                       </execution>
                   </executions>
               </plugin>
           </plugins>
       </build>
   </project>
   ```

1. JAR을 빌드합니다.

   ```
   mvn clean package
   ```

   이렇게 하면 모든 종속성이 포함된 `target/temperature-processor-1.0.0.jar`이 생성됩니다.

1. 배포를 위해 JAR을 S3 버킷에 업로드합니다.

------
#### [ JavaScript ]

Node.js 구성 요소를 모든 종속성으로 패키징하려면:

1. `package.json` 파일 생성:

   ```
   {
     "name": "temperature-processor",
     "version": "1.0.0",
     "description": "Temperature processor component for Greengrass v2",
     "main": "TemperatureProcessor.js",
     "dependencies": {
       "aws-iot-device-sdk-v2": "^1.21.0"
     },
     "engines": {
       "node": ">=14.0.0"
     }
   }
   ```

1. 개발 시스템에 종속성을 설치합니다.

   ```
   npm install
   ```

   이렇게 하면 AWS AWS IoT Device SDK v2가 포함된 `node_modules` 폴더가 생성됩니다.

1. 배포용 패키지:

   ```
   zip -r TemperatureProcessor.zip TemperatureProcessor.js node_modules/ package.json
   ```

1. 배포를 위해 zip 파일을 S3 버킷에 업로드합니다.

**참고**  
Greengrass 디바이스에는 Node.js 런타임(버전 14 이상)이 설치되어 있어야 합니다. 구성 요소 아티팩트`npm install`에는 번들링된 `node_modules` 폴더의 모든 종속성이 포함되므로 Greengrass 코어 디바이스에서를 실행할 필요가 없습니다.

------
#### [ C ]

**사전 조건**:

SDK와 구성 요소를 빌드하려면 다음과 같은 빌드 종속성이 필요합니다.
+ GCC 또는 Clang
+ CMake(최소 버전 3.22)
+ 또는 Ninja 만들기

**빌드 종속성 설치:**

Ubuntu/Debian의 경우:

```
sudo apt install build-essential cmake
```

Amazon Linux에서:

```
sudo yum install gcc cmake make
```

**구성 요소에 대한 CMakeLists.txt 파일을 생성합니다.**

```
cmake_minimum_required(VERSION 3.10)
project(TemperatureProcessor C)

set(CMAKE_C_STANDARD 11)

# Add AWS Greengrass Component SDK
add_subdirectory(aws-greengrass-component-sdk)

# Build your component executable
add_executable(temperature_processor temperature_processor.c)
target_link_libraries(temperature_processor gg-sdk)
```

**빌드 단계:**

```
# Clone the AWS Greengrass Component SDK into your project
git clone https://github.com/aws-greengrass/aws-greengrass-component-sdk.git

# Build your component
cmake -B build -D CMAKE_BUILD_TYPE=MinSizeRel
make -C build -j$(nproc)

# The binary 'temperature_processor' is in ./build/
# Upload this binary to S3 for deployment
```

------
#### [ C\$1\$1 ]

**사전 조건**:

SDK와 구성 요소를 빌드하려면 다음과 같은 빌드 종속성이 필요합니다.
+ C\$1\$120을 지원하는 GCC 또는 Clang
+ CMake(최소 버전 3.22)
+ 또는 Ninja 만들기

**빌드 종속성 설치:**

Ubuntu/Debian의 경우:

```
sudo apt install build-essential cmake
```

Amazon Linux에서:

```
sudo yum install gcc-c++ cmake make
```

**구성 요소에 대한 CMakeLists.txt 파일을 생성합니다.**

```
cmake_minimum_required(VERSION 3.10)
project(TemperatureProcessor CXX)

set(CMAKE_CXX_STANDARD 20)

# Add SDK as subdirectory
add_subdirectory(aws-greengrass-component-sdk)

# Add C++ SDK subdirectory
add_subdirectory(aws-greengrass-component-sdk/cpp)

add_executable(temperature_processor temperature_processor.cpp)
target_link_libraries(temperature_processor gg-sdk++)
```

**빌드 단계:**

```
# Clone the AWS Greengrass Component SDK into your project
git clone https://github.com/aws-greengrass/aws-greengrass-component-sdk.git

# Build your component
cmake -B build -D CMAKE_BUILD_TYPE=MinSizeRel
make -C build -j$(nproc)

# The binary 'temperature_processor' will be in ./build/
# Upload this binary to S3 for deployment
```

------

##### 3. 구성 요소 레시피
<a name="lite-example-1-component-recipe"></a>

구성 요소에서 사용하는 실제 주제로 "리소스" 배열을 업데이트합니다.

------
#### [ Python ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.TemperatureProcessor",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives sensor data and forwards alerts to AlertHandler",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.TemperatureProcessor:pubsub:1": {
            "policyDescription": "Allows access to subscribe to sensor topics",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "sensors/temperature"
            ]
          },
          "com.example.TemperatureProcessor:pubsub:2": {
            "policyDescription": "Allows access to publish to alert topics",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "component/alerts"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "python3 -u {artifacts:path}/temperature_processor.py"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.TemperatureProcessor/1.0.0/temperature_processor.py"
        }
      ]
    }
  ]
}
```

------
#### [ Java ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.TemperatureProcessor",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives sensor data and forwards alerts to AlertHandler",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.TemperatureProcessor:pubsub:1": {
            "policyDescription": "Allows access to subscribe to sensor topics",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "sensors/temperature"
            ]
          },
          "com.example.TemperatureProcessor:pubsub:2": {
            "policyDescription": "Allows access to publish to alert topics",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "component/alerts"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "java -jar {artifacts:path}/TemperatureProcessor.jar"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.TemperatureProcessor/1.0.0/TemperatureProcessor.jar"
        }
      ]
    }
  ]
}
```

------
#### [ JavaScript ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.TemperatureProcessor",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives sensor data and forwards alerts to AlertHandler",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.TemperatureProcessor:pubsub:1": {
            "policyDescription": "Allows access to subscribe to sensor topics",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "sensors/temperature"
            ]
          },
          "com.example.TemperatureProcessor:pubsub:2": {
            "policyDescription": "Allows access to publish to alert topics",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "component/alerts"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "cd {artifacts:decompressedPath}/TemperatureProcessor && node TemperatureProcessor.js"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.TemperatureProcessor/1.0.0/TemperatureProcessor.zip",
          "Unarchive": "ZIP"
        }
      ]
    }
  ]
}
```

------
#### [ C/C\$1\$1 ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.TemperatureProcessor",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives sensor data and forwards alerts to AlertHandler",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.TemperatureProcessor:pubsub:1": {
            "policyDescription": "Allows access to subscribe to sensor topics",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "sensors/temperature"
            ]
          },
          "com.example.TemperatureProcessor:pubsub:2": {
            "policyDescription": "Allows access to publish to alert topics",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "component/alerts"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/temperature_processor"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.TemperatureProcessor/1.0.0/temperature_processor"
        }
      ]
    }
  ]
}
```

------

### 시나리오 2: 클라우드 통신
<a name="lite-example-cloud-communication"></a>

이 시나리오는와 통신하는 V1 Lambda 함수를 V2 일반 구성 요소로 변환하는 AWS IoT Core 방법을 보여줍니다.

#### 애플리케이션 아키텍처
<a name="lite-example-2-scenario"></a>

이 예제에서는 클라우드 연결 아키텍처를 사용합니다.
+ AWS IoT Core 는 디바이스에 명령을 전송합니다.
+ 컨트롤러 Lambda가 명령을 수신하고 처리합니다.
+ 컨트롤러 Lambda가 원격 측정 데이터를 로 다시 전송 AWS IoT Core

이 예제에서는 컨트롤러 Lambda에 중점을 둡니다. 컨트롤러 Lambda는에서 메시지를 수신하고에 메시지를 게시하는 것을 모두 보여줍니다 AWS IoT Core.

##### V1 그룹 구독
<a name="lite-example-2-v1-subscriptions"></a>

에서 AWS IoT Greengrass V1다음 그룹 구독은 Lambda 함수와 간의 통신을 활성화합니다 AWS IoT Core.

구독 1: IoT Cloud → Lambda
+ 소스: IoT Cloud
+ 대상: Lambda(DeviceController)
+ 주제: 명령/device1

구독 2: Lambda → IoT Cloud
+ 소스: Lambda(DeviceController)
+ 대상: IoT Cloud
+ 주제: 원격 측정/디바이스1

#### 컨트롤러 Lambda 함수(V1)
<a name="lite-example-2-v1-code"></a>

------
#### [ Python ]

```
import greengrasssdk
import json
import time

iot_client = greengrasssdk.client('iot-data')

def lambda_handler(event, context):
    """
    Receives commands from IoT Core,
    processes them, and sends telemetry back to cloud
    """
    # Receive command from IoT Core.
    command = event.get('command')
    device_id = event.get('device_id', 'device1')

    print(f"Received command from cloud: {command}")

    # Process command.
    if command == 'get_status':
        status = get_device_status()

        # Send telemetry back to IoT Core.
        telemetry_data = {
            'device_id': device_id,
            'status': status,
            'timestamp': time.time()
        }

        iot_client.publish(
            topic=f'telemetry/{device_id}',
            payload=json.dumps(telemetry_data)
        )

        print(f"Telemetry sent to cloud: {telemetry_data}")

    return {'statusCode': 200}

def get_device_status():
    """Get current device status"""
    # Simulate getting device status.
    return 'online'
```

------
#### [ Java ]

```
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.greengrass.javasdk.IotDataClient;
import com.amazonaws.greengrass.javasdk.model.PublishRequest;
import com.google.gson.Gson;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class DeviceControllerLambda {
    private static final Gson gson = new Gson();
    private final IotDataClient iotDataClient;

    public DeviceControllerLambda() {
        this.iotDataClient = new IotDataClient();
    }

    public String handleRequest(Map<String, Object> event, Context context) {
        /*
         * Receives commands from IoT Core,
         * processes them, and sends telemetry back to cloud
         */

        // Receive command from IoT Core.
        String command = (String) event.get("command");
        String deviceId = event.containsKey("device_id") ? 
            (String) event.get("device_id") : "device1";

        System.out.println("Received command from cloud: " + command);

        // Process command.
        if ("get_status".equals(command)) {
            String status = getDeviceStatus();

            // Send telemetry back to IoT Core.
            Map<String, Object> telemetryData = new HashMap<>();
            telemetryData.put("device_id", deviceId);
            telemetryData.put("status", status);
            telemetryData.put("timestamp", System.currentTimeMillis() / 1000.0);

            String payload = gson.toJson(telemetryData);
            PublishRequest publishRequest = new PublishRequest()
                .withTopic("telemetry/" + deviceId)
                .withPayload(ByteBuffer.wrap(payload.getBytes(StandardCharsets.UTF_8)));

            iotDataClient.publish(publishRequest);

            System.out.println("Telemetry sent to cloud: " + telemetryData);
        }

        return "Success";
    }

    private String getDeviceStatus() {
        // Simulate getting device status.
        return "online";
    }
}
```

------
#### [ JavaScript ]

```
const greengrasssdk = require('aws-greengrass-core-sdk');

const iotClient = new greengrasssdk.IotData();

/**
 * Receives commands from IoT Core and sends telemetry back.
 */
exports.handler = function(event, context) {
    console.log('Received command from IoT Core:', JSON.stringify(event));
    
    const command = event.command;
    const deviceId = event.device_id || 'device1';
    
    console.log(`Processing command: ${command}`);
    
    if (command === 'get_status') {
        const status = 'online';
        
        const telemetryData = {
            device_id: deviceId,
            status: status,
            timestamp: Date.now() / 1000
        };
        
        // Publish telemetry to IoT Core using greengrasssdk.
        const params = {
            topic: `telemetry/${deviceId}`,
            payload: JSON.stringify(telemetryData)
        };
        
        iotClient.publish(params, (err) => {
            if (err) {
                console.error('Error publishing telemetry:', err);
                context.fail(err);
            } else {
                console.log('Telemetry sent to IoT Core:', JSON.stringify(telemetryData));
                context.succeed('Success');
            }
        });
    } else {
        context.succeed('Success');
    }
};
```

------
#### [ C ]

```
#include <aws/greengrass/greengrasssdk.h>
#include <stdio.h>
#include <string.h>
#include <jansson.h>
#include <time.h>

static aws_greengrass_iot_data_client *iot_client = NULL;

const char* get_device_status(void) {
    // Simulate getting device status.
    return "online";
}

void on_cloud_command(const char *topic, const uint8_t *payload, size_t payload_len, void *user_data) {
    // Parse incoming command from IoT Core.
    char *payload_str = strndup((char *)payload, payload_len);
    json_error_t error;
    json_t *event = json_loads(payload_str, 0, &error);
    free(payload_str);
    
    if (!event) {
        fprintf(stderr, "Error parsing JSON: %s\n", error.text);
        return;
    }
    
    // Extract command and device_id.
    json_t *command_obj = json_object_get(event, "command");
    json_t *device_id_obj = json_object_get(event, "device_id");
    
    const char *command = json_string_value(command_obj);
    const char *device_id = device_id_obj ? json_string_value(device_id_obj) : "device1";
    
    printf("Received command from cloud: %s\n", command);
    
    // Process command.
    if (command && strcmp(command, "get_status") == 0) {
        const char *status = get_device_status();
        
        // Send telemetry back to IoT Core.
        json_t *telemetry_data = json_object();
        json_object_set_new(telemetry_data, "device_id", json_string(device_id));
        json_object_set_new(telemetry_data, "status", json_string(status));
        json_object_set_new(telemetry_data, "timestamp", json_real(time(NULL)));
        
        char *telemetry_payload = json_dumps(telemetry_data, JSON_COMPACT);
        
        // Publish telemetry to IoT Core.
        char telemetry_topic[256];
        snprintf(telemetry_topic, sizeof(telemetry_topic), "telemetry/%s", device_id);
        
        aws_greengrass_publish_params params = {
            .topic = telemetry_topic,
            .payload = (uint8_t *)telemetry_payload,
            .payload_len = strlen(telemetry_payload)
        };
        
        aws_greengrass_iot_data_publish(iot_client, &params);
        
        printf("Telemetry sent to cloud: %s\n", telemetry_payload);
    
        free(telemetry_payload);
        json_decref(telemetry_data);
    }
    
    json_decref(event);
}

int main(int argc, char *argv[]) {
    // Initialize Greengrass SDK.
    iot_client = aws_greengrass_iot_data_client_new();
    
    // Subscribe to commands from IoT Core.
    aws_greengrass_subscribe_params subscribe_params = {
        .topic = "commands/device1",
        .callback = on_cloud_command,
        .user_data = NULL
    };
    
    aws_greengrass_iot_data_subscribe(iot_client, &subscribe_params);
    
    printf("Device Controller Lambda started\n");
    printf("Subscribed to commands/device1\n");
    printf("Waiting for commands from IoT Core...\n");
    
    // Keep the Lambda running.
    while (1) {
        sleep(1);
    }
    
    return 0;
}
```

------
#### [ C\$1\$1 ]

```
#include <aws/greengrass/greengrasssdk.h>
#include <iostream>
#include <string>
#include <memory>
#include <jansson.h>
#include <ctime>
#include <unistd.h>

class DeviceController {
private:
    std::unique_ptr<aws_greengrass_iot_data_client, decltype(&aws_greengrass_iot_data_client_destroy)> iot_client;
    
    static void message_callback_wrapper(const char *topic, const uint8_t *payload, 
                                        size_t payload_len, void *user_data) {
        auto* controller = static_cast<DeviceController*>(user_data);
        controller->on_cloud_command(topic, payload, payload_len);
    }
    
    std::string get_device_status() {
        // Simulate getting device status.
        return "online";
    }

public:
    DeviceController() 
        : iot_client(aws_greengrass_iot_data_client_new(), 
                     aws_greengrass_iot_data_client_destroy) {
        if (!iot_client) {
            throw std::runtime_error("Failed to create Greengrass IoT client");
        }
    }
    
    void on_cloud_command(const char *topic, const uint8_t *payload, size_t payload_len) {
        // Parse incoming command from IoT Core.
        std::string payload_str(reinterpret_cast<const char*>(payload), payload_len);
        
        json_error_t error;
        json_t *event = json_loads(payload_str.c_str(), 0, &error);
        
        if (!event) {
            std::cerr << "Error parsing JSON: " << error.text << std::endl;
            return;
        }
        
        // Extract command and device_id.
        json_t *command_obj = json_object_get(event, "command");
        json_t *device_id_obj = json_object_get(event, "device_id");
        
        const char *command = json_string_value(command_obj);
        const char *device_id = device_id_obj ? json_string_value(device_id_obj) : "device1";
        
        std::cout << "Received command from cloud: " << command << std::endl;
        
        // Process command.
        if (command && std::string(command) == "get_status") {
            std::string status = get_device_status();
            
            // Send telemetry back to IoT Core.
            json_t *telemetry_data = json_object();
            json_object_set_new(telemetry_data, "device_id", json_string(device_id));
            json_object_set_new(telemetry_data, "status", json_string(status.c_str()));
            json_object_set_new(telemetry_data, "timestamp", json_real(std::time(nullptr)));
            
            char *telemetry_payload = json_dumps(telemetry_data, JSON_COMPACT);
            
            // Publish telemetry to IoT Core.
            std::string telemetry_topic = "telemetry/" + std::string(device_id);
            
            aws_greengrass_publish_params params = {
                .topic = telemetry_topic.c_str(),
                .payload = reinterpret_cast<uint8_t*>(telemetry_payload),
                .payload_len = strlen(telemetry_payload)
            };
            
            aws_greengrass_iot_data_publish(iot_client.get(), &params);
            
            std::cout << "Telemetry sent to cloud: " << telemetry_payload << std::endl;
            
            free(telemetry_payload);
            json_decref(telemetry_data);
        }
        
        json_decref(event);
    }
    
    void subscribe_to_topic(const std::string& topic) {
        aws_greengrass_subscribe_params subscribe_params = {
            .topic = topic.c_str(),
            .callback = message_callback_wrapper,
            .user_data = this
        };
        
        aws_greengrass_iot_data_subscribe(iot_client.get(), &subscribe_params);
        
        std::cout << "Device Controller Lambda started" << std::endl;
        std::cout << "Subscribed to " << topic << std::endl;
        std::cout << "Waiting for commands from IoT Core..." << std::endl;
    }
    
    void run() {
        // Keep the Lambda running.
        while (true) {
            sleep(1);
        }
    }
};

int main(int argc, char *argv[]) {
    try {
        DeviceController controller;
        controller.subscribe_to_topic("commands/device1");
        controller.run();
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return 1;
    }
    
    return 0;
}
```

------

#### 일반 구성 요소(V2)
<a name="lite-example-2-v2-code"></a>

에서 동일한 기능을 구현하려면 다음을 사용하여 일반 구성 요소를 AWS IoT Greengrass V2생성합니다.

##### 1. 구성 요소 코드
<a name="lite-example-2-component-code"></a>

------
#### [ Python ]

사전 조건:이 구성 요소 코드를 사용하기 전에 Greengrass 디바이스에 Python AWS IoT Device SDK 용를 설치하고 확인합니다.

```
# Install the SDK
pip3 install awsiotsdk

# Verify installation
python3 -c "import awsiot.greengrasscoreipc.clientv2; print('SDK installed successfully')"
```

설치 중에 종속성 충돌이 발생하는 경우 특정 버전의를 설치해 보십시오 AWS IoT Device SDK.

확인 명령이 "SDK installed successfully"를 인쇄하면 구성 요소 코드를 사용할 준비가 된 것입니다.

```
from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
from awsiot.greengrasscoreipc.model import QOS
import json
import time

ipc_client = GreengrassCoreIPCClientV2()

def on_command(event):
    """
    Receives commands from IoT Core,
    processes them, and sends telemetry back to cloud
    """
    try:
        # Receive command from IoT Core.
        data = json.loads(event.message.payload.decode('utf-8'))
        command = data.get('command')
        device_id = data.get('device_id', 'device1')

        print(f"Received command from cloud: {command}")

        # Process command.
        if command == 'get_status':
            status = get_device_status()

            # Send telemetry back to IoT Core.
            telemetry_data = {
                'device_id': device_id,
                'status': status,
                'timestamp': time.time()
            }

            ipc_client.publish_to_iot_core(
                topic_name=f'telemetry/{device_id}',
                qos=QOS.AT_LEAST_ONCE,
                payload=json.dumps(telemetry_data).encode('utf-8')
            )

            print(f"Telemetry sent to cloud: {telemetry_data}")

    except Exception as e:
        print(f"Error processing command: {e}")

def get_device_status():
    """Get current device status"""
    # Simulate getting device status.
    return 'online'

def main():
    print("Device Controller component starting...")

    # Subscribe to commands from IoT Core.
    ipc_client.subscribe_to_iot_core(
        topic_name='commands/device1',
        qos=QOS.AT_LEAST_ONCE,
        on_stream_event=on_command
    )

    print("Subscribed to commands/device1 from IoT Core")
    print("Waiting for commands from cloud...")

    # Keep running.
    while True:
        time.sleep(1)

if __name__ == '__main__':
    main()
```

------
#### [ Java ]

```
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClientV2;
import software.amazon.awssdk.aws.greengrass.model.QOS;
import software.amazon.awssdk.aws.greengrass.model.SubscribeToIoTCoreRequest;
import software.amazon.awssdk.aws.greengrass.model.IoTCoreMessage;
import software.amazon.awssdk.aws.greengrass.model.PublishToIoTCoreRequest;
import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class DeviceController {
    private static GreengrassCoreIPCClientV2 ipcClient;

    public static void main(String[] args) {
        System.out.println("Device Controller component starting...");
        
        try (GreengrassCoreIPCClientV2 client = GreengrassCoreIPCClientV2.builder().build()) {
            ipcClient = client;

            SubscribeToIoTCoreRequest subscribeRequest = new SubscribeToIoTCoreRequest()
                .withTopicName("commands/device1")
                .withQos(QOS.AT_LEAST_ONCE);

            ipcClient.subscribeToIoTCore(
                subscribeRequest,
                DeviceController::onCommand,
                Optional.empty(),
                Optional.empty()
            );

            System.out.println("Subscribed to commands/device1 from IoT Core");
            System.out.println("Waiting for commands from cloud...");

            while (true) {
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        }
    }

    public static void onCommand(IoTCoreMessage message) {
        try {
            String payload = new String(message.getMessage().getPayload(), StandardCharsets.UTF_8);
            
            // Simple JSON parsing.
            String command = extractJsonValue(payload, "command");
            String deviceId = extractJsonValue(payload, "device_id");
            if (deviceId == null || deviceId.isEmpty()) {
                deviceId = "device1";
            }

            System.out.println("Received command from cloud: " + command);

            if ("get_status".equals(command)) {
                String status = getDeviceStatus();

                // Build JSON manually.
                String telemetryJson = String.format(
                    "{\"device_id\":\"%s\",\"status\":\"%s\",\"timestamp\":%.3f}",
                    deviceId, status, System.currentTimeMillis() / 1000.0
                );
                byte[] telemetryBytes = telemetryJson.getBytes(StandardCharsets.UTF_8);

                PublishToIoTCoreRequest publishRequest = new PublishToIoTCoreRequest()
                    .withTopicName("telemetry/" + deviceId)
                    .withQos(QOS.AT_LEAST_ONCE)
                    .withPayload(telemetryBytes);

                ipcClient.publishToIoTCore(publishRequest);

                System.out.println("Telemetry sent to cloud: " + telemetryJson);
            }
        } catch (Exception e) {
            System.err.println("Error processing command: " + e.getMessage());
        }
    }

    private static String extractJsonValue(String json, String key) {
        Pattern pattern = Pattern.compile("\"" + Pattern.quote(key) + "\"\\s*:\\s*\"([^\"]+)\"");
        Matcher matcher = pattern.matcher(json);
        return matcher.find() ? matcher.group(1) : null;
    }

    private static String getDeviceStatus() {
        return "online";
    }
}
```

------
#### [ JavaScript ]

```
const greengrasscoreipc = require('aws-iot-device-sdk-v2').greengrasscoreipc;

class DeviceController {
    constructor() {
        this.ipcClient = null;
    }

    async start() {
        console.log('Device Controller component starting...');
        
        try {
            this.ipcClient = greengrasscoreipc.createClient();
            await this.ipcClient.connect();
            
            const subscribeRequest = {
                topicName: 'commands/device1',
                qos: 1
            };

            const streamingOperation = this.ipcClient.subscribeToIoTCore(subscribeRequest);
            
            streamingOperation.on('message', (message) => {
                this.onCommand(message);
            });
            
            streamingOperation.on('streamError', (error) => {
                console.error('Stream error:', error);
            });
            
            streamingOperation.on('ended', () => {
                console.log('Subscription stream ended');
            });
            
            await streamingOperation.activate();
            
            console.log('Subscribed to commands/device1 from IoT Core');
            console.log('Waiting for commands from cloud...');
            
        } catch (error) {
            console.error('Error starting component:', error);
            process.exit(1);
        }
    }

    async onCommand(message) {
        try {
            const payload = message.message.payload.toString('utf-8');
            const data = JSON.parse(payload);
            
            const command = data.command;
            const deviceId = data.device_id || 'device1';
            
            console.log(`Received command from cloud: ${command}`);
            
            if (command === 'get_status') {
                const status = this.getDeviceStatus();
                
                const telemetryData = {
                    device_id: deviceId,
                    status: status,
                    timestamp: Date.now() / 1000
                };
                
                const telemetryJson = JSON.stringify(telemetryData);
                
                const publishRequest = {
                    topicName: `telemetry/${deviceId}`,
                    qos: 1,
                    payload: Buffer.from(telemetryJson, 'utf-8')
                };
                
                await this.ipcClient.publishToIoTCore(publishRequest);
                console.log(`Telemetry sent to cloud: ${telemetryJson}`);
            }
            
        } catch (error) {
            console.error('Error processing command:', error);
        }
    }

    getDeviceStatus() {
        return 'online';
    }
}

// Start the component.
const controller = new DeviceController();
controller.start();
```

------
#### [ C ]

```
#include <gg/buffer.h>
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/map.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>

#define COMMAND_TOPIC "commands/device1"
#define TELEMETRY_TOPIC "telemetry/device1"

typedef struct {
    char device_id[64];
    char command[64];
} CommandData;

static pthread_mutex_t command_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t command_cond = PTHREAD_COND_INITIALIZER;
static CommandData pending_command;
static bool has_pending_command = false;

const char* get_device_status(void) {
    // Simulate getting device status.
    return "online";
}

static void *telemetry_publisher_thread(void *arg) {
    (void) arg;
    
    while (true) {
        pthread_mutex_lock(&command_mutex);
        while (!has_pending_command) {
            pthread_cond_wait(&command_cond, &command_mutex);
        }
        
        CommandData cmd = pending_command;
        has_pending_command = false;
        pthread_mutex_unlock(&command_mutex);
        
        // Process command.
        if (strcmp(cmd.command, "get_status") == 0) {
            const char *status = get_device_status();
            
            // Create telemetry JSON string.
            char telemetry_json[512];
            snprintf(telemetry_json, sizeof(telemetry_json),
                     "{\"device_id\":\"%s\",\"status\":\"%s\",\"timestamp\":%ld}",
                     cmd.device_id, status, time(NULL));
            
            GgBuffer telemetry_buf = {
                .data = (uint8_t *)telemetry_json,
                .len = strlen(telemetry_json)
            };
            
            // Publish telemetry to IoT Core.
            GgError ret = ggipc_publish_to_iot_core(GG_STR(TELEMETRY_TOPIC), telemetry_buf, 0);
            
            if (ret != GG_ERR_OK) {
                fprintf(stderr, "Failed to publish telemetry to IoT Core\n");
            } else {
                printf("Telemetry sent to cloud: device_id=%s, status=%s\n", cmd.device_id, status);
            }
        }
    }
    
    return NULL;
}

static void on_cloud_command(
    void *ctx, GgBuffer topic, GgBuffer payload, GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) topic;
    (void) handle;
    
    printf("Received command from IoT Core: %.*s\n", (int)payload.len, payload.data);
    
    // Parse JSON payload (comes as raw buffer from IoT Core).
    // For simplicity, we'll do basic string parsing.
    
    // Extract command and device_id from JSON string.
    char payload_str[512];
    snprintf(payload_str, sizeof(payload_str), "%.*s", (int)payload.len, payload.data);
    
    // Simple JSON parsing (looking for "command":"get_status").
    char *command_start = strstr(payload_str, "\"command\"");
    char *device_id_start = strstr(payload_str, "\"device_id\"");
    
    if (command_start) {
        pthread_mutex_lock(&command_mutex);
        
        char *cmd_value = strstr(command_start, ":");
        if (cmd_value) {
            cmd_value = strchr(cmd_value, '"');
            if (cmd_value) {
                cmd_value++;
                char *cmd_end = strchr(cmd_value, '"');
                if (cmd_end) {
                    size_t cmd_len = cmd_end - cmd_value;
                    if (cmd_len < sizeof(pending_command.command)) {
                        strncpy(pending_command.command, cmd_value, cmd_len);
                        pending_command.command[cmd_len] = '\0';
                    }
                }
            }
        }
        
        // Extract device_id or use default.
        if (device_id_start) {
            char *dev_value = strstr(device_id_start, ":");
            if (dev_value) {
                dev_value = strchr(dev_value, '"');
                if (dev_value) {
                    dev_value++;
                    char *dev_end = strchr(dev_value, '"');
                    if (dev_end) {
                        size_t dev_len = dev_end - dev_value;
                        if (dev_len < sizeof(pending_command.device_id)) {
                            strncpy(pending_command.device_id, dev_value, dev_len);
                            pending_command.device_id[dev_len] = '\0';
                        }
                    }
                }
            }
        } else {
            strcpy(pending_command.device_id, "device1");
        }
        
        printf("Received command from cloud: %s\n", pending_command.command);
        
        has_pending_command = true;
        pthread_cond_signal(&command_cond);
        pthread_mutex_unlock(&command_mutex);
    }
}

int main(void) {
    setvbuf(stdout, NULL, _IONBF, 0);
    printf("Device Controller component starting...\n");
    
    gg_sdk_init();
    
    GgError ret = ggipc_connect();
    if (ret != GG_ERR_OK) {
        fprintf(stderr, "Failed to connect to Greengrass nucleus\n");
        exit(1);
    }
    printf("Connected to Greengrass IPC\n");
    
    // Start telemetry publisher thread.
    pthread_t telemetry_thread;
    if (pthread_create(&telemetry_thread, NULL, telemetry_publisher_thread, NULL) != 0) {
        fprintf(stderr, "Failed to create telemetry publisher thread\n");
        exit(1);
    }
    
    // Subscribe to commands from IoT Core.
    GgIpcSubscriptionHandle handle;
    ret = ggipc_subscribe_to_iot_core(
        GG_STR(COMMAND_TOPIC),
        0,
        &on_cloud_command,
        NULL,
        &handle
    );
    
    if (ret != GG_ERR_OK) {
        fprintf(stderr, "Failed to subscribe to IoT Core topic\n");
        exit(1);
    }
    
    printf("Subscribed to %s\n", COMMAND_TOPIC);
    printf("Waiting for commands from IoT Core...\n");
    
    while (true) {
        sleep(1);
    }
    
    return 0;
}
```

------
#### [ C\$1\$1 ]

```
#include <gg/ipc/client.hpp>
#include <gg/buffer.hpp>
#include <gg/object.hpp>
#include <gg/types.hpp>

#include <chrono>
#include <condition_variable>
#include <ctime>
#include <iostream>
#include <mutex>
#include <string>
#include <string_view>
#include <thread>

constexpr std::string_view COMMAND_TOPIC = "commands/device1";
constexpr std::string_view TELEMETRY_TOPIC = "telemetry/device1";

struct CommandData {
    std::string device_id;
    std::string command;
};

static std::mutex command_mutex;
static std::condition_variable command_cv;
static CommandData pending_command;
static bool has_pending_command = false;

std::string get_device_status() {
    // Simulate getting device status.
    return "online";
}

void telemetry_publisher_thread() {
    auto& client = gg::ipc::Client::get();
    
    while (true) {
        std::unique_lock<std::mutex> lock(command_mutex);
        command_cv.wait(lock, [] { return has_pending_command; });
        
        CommandData cmd = pending_command;
        has_pending_command = false;
        lock.unlock();
        
        // Process command.
        if (cmd.command == "get_status") {
            std::string status = get_device_status();
            
            // Get current timestamp.
            auto now = std::time(nullptr);
            
            // Create telemetry JSON payload.
            std::string telemetry_payload = "{\"device_id\":\"" + cmd.device_id + 
                                          "\",\"status\":\"" + status + 
                                          "\",\"timestamp\":" + std::to_string(now) + "}";
            
            // Publish telemetry to IoT Core.
            gg::Buffer telemetry_buffer(telemetry_payload);
            auto error = client.publish_to_iot_core(TELEMETRY_TOPIC, telemetry_buffer);
            
            if (error) {
                std::cerr << "Failed to publish telemetry to IoT Core: " 
                         << error.message() << std::endl;
            } else {
                std::cout << "Telemetry sent to cloud: device_id=" << cmd.device_id 
                         << ", status=" << status << std::endl;
            }
        }
    }
}

class CloudCommandCallback : public gg::ipc::IoTCoreTopicCallback {
    void operator()(
        std::string_view topic,
        gg::Object payload,
        gg::ipc::Subscription& handle
    ) override {
        (void) topic;
        (void) handle;
        
        // Payload is a Buffer containing JSON string from IoT Core.
        if (payload.index() != GG_TYPE_BUF) {
            std::cerr << "Expected Buffer message\n";
            return;
        }
        
        // Extract buffer.
        auto buffer = gg::get<std::span<uint8_t>>(payload);
        std::string json_str(reinterpret_cast<const char*>(buffer.data()), buffer.size());
        
        std::cout << "Received command from IoT Core: " << json_str << std::endl;
        
        // Simple JSON parsing for demo.
        std::string command;
        std::string device_id = "device1";  // Default
        
        // Extract command.
        size_t cmd_pos = json_str.find("\"command\":");
        if (cmd_pos != std::string::npos) {
            size_t start = json_str.find("\"", cmd_pos + 10) + 1;
            size_t end = json_str.find("\"", start);
            if (end != std::string::npos) {
                command = json_str.substr(start, end - start);
            }
        }
        
        // Extract device_id if present.
        size_t dev_pos = json_str.find("\"device_id\":");
        if (dev_pos != std::string::npos) {
            size_t start = json_str.find("\"", dev_pos + 12) + 1;
            size_t end = json_str.find("\"", start);
            if (end != std::string::npos) {
                device_id = json_str.substr(start, end - start);
            }
        }
        
        if (!command.empty()) {
            std::lock_guard<std::mutex> lock(command_mutex);
            pending_command = {device_id, command};
            has_pending_command = true;
            command_cv.notify_one();
            
            std::cout << "Received command from cloud: " << command << std::endl;
        }
    }
};

int main() {
    // Disable stdout buffering for real-time logging in systemd/Greengrass.
    std::cout.setf(std::ios::unitbuf);
    
    std::cout << "Device Controller component starting..." << std::endl;
    
    auto& client = gg::ipc::Client::get();
    
    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to connect to Greengrass nucleus: " 
                 << error.message() << std::endl;
        return 1;
    }
    
    std::cout << "Connected to Greengrass IPC" << std::endl;
    
    // Start telemetry publisher thread.
    std::thread telemetry_thread(telemetry_publisher_thread);
    telemetry_thread.detach();
    
    // Subscribe to commands from IoT Core.
    static CloudCommandCallback handler;
    error = client.subscribe_to_iot_core(COMMAND_TOPIC, handler);
    
    if (error) {
        std::cerr << "Failed to subscribe to IoT Core topic: " 
                 << error.message() << std::endl;
        return 1;
    }
    
    std::cout << "Subscribed to " << COMMAND_TOPIC << std::endl;
    std::cout << "Waiting for commands from IoT Core..." << std::endl;
    
    // Keep running.
    while (true) {
        using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s);
    }
    
    return 0;
}
```

------

##### 2. 구성 요소 빌드 및 패키징
<a name="lite-example-2-build-component"></a>

일부 언어는 배포 전에 빌드 또는 패키징이 필요합니다.

------
#### [ Python ]

Python은 컴파일이 필요하지 않습니다. 구성 요소는 .py 파일을 직접 사용할 수 있습니다.

------
#### [ Java ]

모든 종속성이 번들로 제공되는 실행 파일 JAR을 빌드하려면:

1. 프로젝트 디렉터리에 `pom.xml` 파일을 생성합니다.

   ```
   <?xml version="1.0" encoding="UTF-8"?>
   <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
   
       <!-- Basic project information: organization, component name, and version -->
       <groupId>com.example</groupId>
       <artifactId>device-controller</artifactId>
       <version>1.0.0</version>
   
       <properties>
           <!-- Java 11 LTS (Long Term Support) is recommended for Greengrass v2 components -->
           <maven.compiler.source>11</maven.compiler.source>
           <maven.compiler.target>11</maven.compiler.target>
       </properties>
   
       <dependencies>
           <!-- AWS IoT Device SDK for Java - provides IPC client for Greengrass v2 cloud communication -->
           <dependency>
               <groupId>software.amazon.awssdk.iotdevicesdk</groupId>
               <artifactId>aws-iot-device-sdk</artifactId>
               <version>1.25.1</version>
           </dependency>
       </dependencies>
   
       <build>
           <plugins>
               <!-- Maven Shade Plugin - creates a standalone JAR with all dependencies included for Greengrass deployment -->
               <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-shade-plugin</artifactId>
                   <version>3.2.4</version>
                   <executions>
                       <execution>
                           <phase>package</phase>
                           <goals>
                               <goal>shade</goal>
                           </goals>
                           <configuration>
                               <transformers>
                                   <!-- Set the main class for the executable JAR -->
                                   <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                       <mainClass>DeviceController</mainClass>
                                   </transformer>
                               </transformers>
                               <filters>
                                   <!-- Exclude signature files to avoid security exceptions -->
                                   <filter>
                                       <artifact>*:*</artifact>
                                       <excludes>
                                           <exclude>META-INF/*.SF</exclude>
                                           <exclude>META-INF/*.DSA</exclude>
                                           <exclude>META-INF/*.RSA</exclude>
                                       </excludes>
                                   </filter>
                               </filters>
                           </configuration>
                       </execution>
                   </executions>
               </plugin>
           </plugins>
       </build>
   </project>
   ```

1. JAR을 빌드합니다.

   ```
   mvn clean package
   ```

   이렇게 하면 모든 종속성이 포함된 `target/device-controller-1.0.0.jar`이 생성됩니다.

1. 배포를 위해 JAR을 S3 버킷에 업로드합니다.

------
#### [ JavaScript ]

Node.js 구성 요소를 모든 종속성으로 패키징하려면:

1. `package.json` 파일 생성:

   ```
   {
     "name": "device-controller",
     "version": "1.0.0",
     "description": "Device controller component for Greengrass v2",
     "main": "DeviceController.js",
     "dependencies": {
       "aws-iot-device-sdk-v2": "^1.21.0"
     },
     "engines": {
       "node": ">=14.0.0"
     }
   }
   ```

1. 개발 시스템에 종속성을 설치합니다.

   ```
   npm install
   ```

   이렇게 하면 AWS AWS IoT Device SDK v2가 포함된 `node_modules` 폴더가 생성됩니다.

1. 배포용 패키지:

   ```
   zip -r DeviceController.zip DeviceController.js node_modules/ package.json
   ```

1. zip 파일을 S3 버킷에 업로드하여 배포합니다.

**참고**  
Greengrass 디바이스에는 Node.js 런타임(버전 14 이상)이 설치되어 있어야 합니다. 구성 요소 아티팩트`npm install`에는 번들링된 `node_modules` 폴더의 모든 종속성이 포함되므로 Greengrass 코어 디바이스에서를 실행할 필요가 없습니다.

------
#### [ C ]

**사전 조건**:

SDK와 구성 요소를 빌드하려면 다음과 같은 빌드 종속성이 필요합니다.
+ GCC 또는 Clang
+ CMake(최소 버전 3.22)
+ 또는 Ninja 만들기

**빌드 종속성 설치:**

Ubuntu/Debian의 경우:

```
sudo apt install build-essential cmake
```

Amazon Linux에서:

```
sudo yum install gcc cmake make
```

**구성 요소에 대한 CMakeLists.txt 파일을 생성합니다.**

```
cmake_minimum_required(VERSION 3.10)
project(DeviceController C)

set(CMAKE_C_STANDARD 11)

# Add AWS Greengrass Component SDK
add_subdirectory(aws-greengrass-component-sdk)

# Build your component executable
add_executable(device_controller device_controller.c)
target_link_libraries(device_controller gg-sdk)
```

**빌드 단계:**

```
# Clone the AWS Greengrass Component SDK into your project
git clone https://github.com/aws-greengrass/aws-greengrass-component-sdk.git

# Build your component
cmake -B build -D CMAKE_BUILD_TYPE=MinSizeRel
make -C build -j$(nproc)

# The binary 'device_controller' is in ./build/
# Upload this binary to S3 for deployment
```

------
#### [ C\$1\$1 ]

**사전 조건**:

SDK와 구성 요소를 빌드하려면 다음과 같은 빌드 종속성이 필요합니다.
+ C\$1\$120을 지원하는 GCC 또는 Clang
+ CMake(최소 버전 3.22)
+ 또는 Ninja 만들기

**빌드 종속성 설치:**

Ubuntu/Debian의 경우:

```
sudo apt install build-essential cmake
```

Amazon Linux에서:

```
sudo yum install gcc-c++ cmake make
```

**구성 요소에 대한 CMakeLists.txt 파일을 생성합니다.**

```
cmake_minimum_required(VERSION 3.10)
project(DeviceController CXX)

set(CMAKE_CXX_STANDARD 20)

# Add SDK as subdirectory
add_subdirectory(aws-greengrass-component-sdk)

# Add C++ SDK subdirectory
add_subdirectory(aws-greengrass-component-sdk/cpp)

add_executable(device_controller device_controller.cpp)
target_link_libraries(device_controller gg-sdk++)
```

**빌드 단계:**

```
# Clone the AWS Greengrass Component SDK into your project
git clone https://github.com/aws-greengrass/aws-greengrass-component-sdk.git

# Build your component
cmake -B build -D CMAKE_BUILD_TYPE=MinSizeRel
make -C build -j$(nproc)

# The binary 'device_controller' will be in ./build/
# Upload this binary to S3 for deployment
```

------

##### 3. 구성 요소 레시피
<a name="lite-example-2-component-recipe"></a>

구성 요소에서 사용하는 실제 주제로 "리소스" 배열을 업데이트합니다.

------
#### [ Python ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.DeviceController",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives commands from IoT Core and sends telemetry back to cloud",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.DeviceController:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to IoT Core topics",
            "operations": [
              "aws.greengrass#SubscribeToIoTCore"
            ],
            "resources": [
              "commands/device1"
            ]
          },
          "com.example.DeviceController:mqttproxy:2": {
            "policyDescription": "Allows access to publish to IoT Core topics",
            "operations": [
              "aws.greengrass#PublishToIoTCore"
            ],
            "resources": [
              "telemetry/device1"
            ]
          }
        }
      }
    }
  },
  "ComponentDependencies": {
    "aws.greengrass.TokenExchangeService": {
      "VersionRequirement": ">=2.0.0",
      "DependencyType": "HARD"
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "python3 -u {artifacts:path}/device_controller.py"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.DeviceController/1.0.0/device_controller.py"
        }
      ]
    }
  ]
}
```

------
#### [ Java ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.DeviceController",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives commands from IoT Core and sends telemetry back to cloud",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.DeviceController:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to IoT Core topics",
            "operations": [
              "aws.greengrass#SubscribeToIoTCore"
            ],
            "resources": [
              "commands/device1"
            ]
          },
          "com.example.DeviceController:mqttproxy:2": {
            "policyDescription": "Allows access to publish to IoT Core topics",
            "operations": [
              "aws.greengrass#PublishToIoTCore"
            ],
            "resources": [
              "telemetry/device1"
            ]
          }
        }
      }
    }
  },
  "ComponentDependencies": {
    "aws.greengrass.TokenExchangeService": {
      "VersionRequirement": ">=2.0.0",
      "DependencyType": "HARD"
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "java -jar {artifacts:path}/DeviceController.jar"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.DeviceController/1.0.0/DeviceController.jar"
        }
      ]
    }
  ]
}
```

------
#### [ JavaScript ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.DeviceController",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives commands from IoT Core and sends telemetry back to cloud",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.DeviceController:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to command topics from IoT Core",
            "operations": [
              "aws.greengrass#SubscribeToIoTCore"
            ],
            "resources": [
              "commands/device1"
            ]
          },
          "com.example.DeviceController:mqttproxy:2": {
            "policyDescription": "Allows access to publish telemetry to IoT Core",
            "operations": [
              "aws.greengrass#PublishToIoTCore"
            ],
            "resources": [
              "telemetry/*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "cd {artifacts:decompressedPath}/DeviceController && node DeviceController.js"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.DeviceController/1.0.0/DeviceController.zip",
          "Unarchive": "ZIP"
        }
      ]
    }
  ]
}
```

------
#### [ C/C\$1\$1 ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.DeviceController",
  "ComponentVersion": "1.0.0",
  "ComponentType": "aws.greengrass.generic",
  "ComponentDescription": "Receives commands from IoT Core and sends telemetry back to cloud",
  "ComponentPublisher": "[Your Company]",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.DeviceController:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to IoT Core topics",
            "operations": ["aws.greengrass#SubscribeToIoTCore"],
            "resources": ["commands/device1"]
          },
          "com.example.DeviceController:mqttproxy:2": {
            "policyDescription": "Allows access to publish to IoT Core topics",
            "operations": ["aws.greengrass#PublishToIoTCore"],
            "resources": ["telemetry/device1"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/device_controller"
      },
      "Artifacts": [
        {
          "Uri": "s3://YOUR-BUCKET/artifacts/com.example.DeviceController/1.0.0/device_controller"
        }
      ]
    }
  ]
}
```

------