

# Migrate from AWS IoT Greengrass Version 1
<a name="migrate-from-v1"></a>

AWS IoT Greengrass Version 2 is a major version release of the AWS IoT Greengrass Core software, APIs, and console. AWS IoT Greengrass V2 introduces several improvements to AWS IoT Greengrass V1, such as modular applications, deployments to large fleets of devices, and support for additional platforms.

**Note**  
End of support notice: On October 7, 2026, AWS will end support for AWS IoT Greengrass Version 1. After October 7, 2026, you will no longer be able to access the AWS IoT Greengrass V1 console or AWS IoT Greengrass V1 resources.

Follow instructions in this guide to migrate from AWS IoT Greengrass V1 to AWS IoT Greengrass V2.

## Migration overview
<a name="migration-overview"></a>

At a high level, you can use the following procedure to upgrade core devices from AWS IoT Greengrass V1 to AWS IoT Greengrass V2.

Before migrating, you'll choose between two runtime options:
+ **Greengrass nucleus** (lower migration effort, full feature support)
+ **Greengrass nucleus lite** (higher migration effort, designed for resource-constrained devices).

The exact procedure that you follow depends on your device resources, required features, and specific environment requirements.

![\[An overview of how to migrate from AWS IoT Greengrass V1 to AWS IoT Greengrass V2.\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/images/migration-workflow-updated.png)


1. 

**[Understand the differences between V1 and V2](greengrass-v1-concept-differences.md)**

   AWS IoT Greengrass V2 introduces new fundamental concepts for device fleets and deployable software, and V2 simplifies several concepts from V1.

   The AWS IoT Greengrass V2 cloud service and AWS IoT Greengrass Core software v2.x aren't backward compatible with the AWS IoT Greengrass V1 cloud service and AWS IoT Greengrass Core software v1.x. As a result, AWS IoT Greengrass V1 over-the-air (OTA) updates can't upgrade core devices from V1 to V2.

1. 

**[Choose your runtime (Greengrass nucleus or Greengrass nucleus lite)](choose-runtime.md)**

   Decide between Greengrass nucleus or Greengrass nucleus lite based on your device resources and feature requirements:
   + **Greengrass nucleus path**: Lower migration effort. Lambda functions can be imported as Lambda components with minimal code changes. Supports V1 features (local shadow service, client devices, connectors).
   + **Greengrass nucleus lite path**: Higher migration effort. Lambda functions need to be converted to generic components, requiring code changes to use AWS IoT Device SDK V2/AWS IoT Greengrass Component SDK instead of AWS IoT Greengrass Core SDK. Does not support local shadow service, client devices, or connectors.

1. 

**[Set up a new device to test V1 applications on V2](set-up-test-device.md)**

   To minimize risk to your devices in production, create a new device to test your V1 applications on V2. Choose the setup guide based on your runtime selection:
   + **Option A - Greengrass nucleus runtime**: [Set up a new device to test V1 applications on V2](set-up-v2-test-device.md). Import Lambda functions as Lambda components with minimal code changes.
   + **Option B - Greengrass nucleus lite runtime**: [Set up a new device to test V1 applications on V2 (Greengrass nucleus lite)](set-up-v2-test-device-lite.md). Convert Lambda functions to generic components using AWS IoT Device SDK.

1. 

**[Upgrade V1 core devices to run V2](upgrade-v1-core-devices.md)**

   After testing on a new device, upgrade your existing V1 core devices to run the AWS IoT Greengrass Core software v2.x and AWS IoT Greengrass V2 components. To migrate a fleet of devices from V1 to V2, you repeat this step for each device in the fleet.

# Differences between AWS IoT Greengrass V1 and AWS IoT Greengrass V2
<a name="greengrass-v1-concept-differences"></a>

AWS IoT Greengrass V2 introduces new fundamental concepts for devices, fleets, and deployable software. This section describes the V1 concepts that are different in V2.


**Greengrass concepts and terminology**  

| Concept | AWS IoT Greengrass V1 | AWS IoT Greengrass V2 | 
| --- | --- | --- | 
|  Application code  |  In AWS IoT Greengrass V1, Lambda functions define the software that runs on core devices. In each Greengrass group, you define subscriptions and local resources that the function uses. For Lambda functions that the AWS IoT Greengrass Core software runs in a containerized Lambda runtime environment, you define container parameters, such as memory limits.  |  In AWS IoT Greengrass V2, *components* are the software modules that run on core devices. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html) You can import your V1 Lambda functions as components that run in a Lambda runtime environment in AWS IoT Greengrass V2. When you import the Lambda function, you specify the subscriptions, local resources, and container parameters for the function. For more information, see [Step 2: Create and deploy AWS IoT Greengrass V2 components to migrate AWS IoT Greengrass V1 applications](set-up-v2-test-device.md#run-v1-applications). For more information about how to create custom components, see [Develop AWS IoT Greengrass components](develop-greengrass-components.md).  | 
|  AWS IoT Greengrass groups and deployments  |  In AWS IoT Greengrass V1, a group defines the core device, the settings and software for that core device, and the list of AWS IoT things that can connect to that core device. You create a deployment to send a group's configuration to a core device.  |  In AWS IoT Greengrass V2, you use *deployments* to define the software components and configurations that run on core devices. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html) For more information, see [Deploy AWS IoT Greengrass components to devices](manage-deployments.md). In AWS IoT Greengrass V2, you can also create local deployments using the [Greengrass CLI](gg-cli.md) to test custom software components on the device where you develop them. For more information, see [Create AWS IoT Greengrass components](create-components.md).  | 
|  AWS IoT Greengrass Core software  |  In AWS IoT Greengrass V1, the AWS IoT Greengrass Core software is a single package that contains the software and all of its features. The edge device on which you install the AWS IoT Greengrass Core software is called a Greengrass core.   |  In AWS IoT Greengrass V2, the AWS IoT Greengrass Core software is modular, so that you can choose what to install to control the memory footprint. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html)  | 
|  Connectors  |  In AWS IoT Greengrass V1, connectors are prebuilt modules that you deploy to AWS IoT Greengrass V1 core devices to interact with local infrastructure, device protocols, AWS, and other cloud services.  |  In AWS IoT Greengrass V2, AWS provides Greengrass components that implement the functionality provided by connectors in V1. The following AWS IoT Greengrass V2 components provide Greengrass V1 connector functionality: [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html) For more information, see [AWS-provided components](public-components.md).  | 
|  Connected devices (Greengrass devices)  |  In AWS IoT Greengrass V1, connected devices are AWS IoT things that you add to a Greengrass group to connect to the core device in that group and communicate over MQTT. You must deploy that group each time that you add or remove a connected device. You use subscriptions to relay messages between connected devices, AWS IoT Core, and applications on the core device.  |  In AWS IoT Greengrass V2, connected devices are called Greengrass client devices. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html) In both AWS IoT Greengrass V1 and AWS IoT Greengrass V2, devices can run [FreeRTOS](https://docs.aws.amazon.com/freertos/latest/userguide/freertos-lib-gg-connectivity.html) or use the [AWS IoT Device SDK](https://docs.aws.amazon.com/iot/latest/developerguide/iot-sdks.html) or [Greengrass discovery API](greengrass-discover-api.md) to get information about core devices to which they can connect. The Greengrass discovery API is backward compatible, so if you have client devices that connect to a V1 core device, you can connect them to a V2 core device without changing their code. For more information about client devices, see [Interact with local IoT devices](interact-with-local-iot-devices.md).  | 
|  Local resources  |  In AWS IoT Greengrass V1, Lambda functions that run in containers can be configured to access volumes and devices on the core device's file system. These file system resources are known as local resources.  |  In AWS IoT Greengrass V2, you can run components that are [Lambda functions](run-lambda-functions.md), [Docker containers](run-docker-container.md), or [native operating system processes or custom runtimes](develop-greengrass-components.md). [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html)  | 
|  Local shadow service  |  In AWS IoT Greengrass V1, the local shadow service is enabled by default, and supports only unnamed classic shadows. You use the AWS IoT Greengrass Core SDK in your Lambda functions to interact with shadows on your devices.  |  In AWS IoT Greengrass V2, you enable the local shadow service by deploying the shadow manager component. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html) For more information, see [Interact with device shadows](interact-with-shadows.md).  | 
|  Subscriptions  |  In AWS IoT Greengrass V1, you define subscriptions for a Greengrass group to specify communication channels between Lambda functions, connectors, connected devices, the AWS IoT Core MQTT broker, and the local shadow service. Subscriptions specify where Lambda functions receive event messages to consume as function payloads.  |  In AWS IoT Greengrass V2, you specify communication channels without using subscriptions. [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-v1-concept-differences.html)  | 
|  Accessing other AWS services  |  In AWS IoT Greengrass V1, you attach an AWS Identity and Access Management (IAM) role, called the group role, to a Greengrass group. The group role defines the permissions that Lambda functions and AWS IoT Greengrass features on that group's core device use to access AWS services.  |  In AWS IoT Greengrass V2, you attach an AWS IoT role alias to a Greengrass core device. The role alias points to an IAM role called the *token exchange role*. The token exchange role defines the permissions that Greengrass components on the core device use to access AWS services. For more information, see [Authorize core devices to interact with AWS services](device-service-role.md).  | 

# Choose your runtime (Greengrass nucleus or Greengrass nucleus lite)
<a name="choose-runtime"></a>

Choosing between Greengrass nucleus and Greengrass nucleus lite depends on your device resources and the features your Lambda functions use. Review the event source compatibility matrix in the following table, then use the decision flow diagram to determine which runtime is appropriate for your migration. For a detailed comparison of Greengrass nucleus and Greengrass nucleus lite features, see [Choosing your runtime](choosing-your-runtime.md).

## Event source compatibility matrix
<a name="event-source-compatibility"></a>

In AWS IoT Greengrass V1, Lambda functions can communicate with five types of event sources: other Lambda functions, AWS IoT Core, local shadow service, client devices, and connectors. The following table shows which of these event sources are supported in each V2 runtime.

Note: Event source names use AWS IoT Greengrass V1 terminology. When migrating to V2, Lambda functions are converted to either Lambda components (supported only in Greengrass nucleus) or generic components (supported in both Greengrass nucleus and Greengrass nucleus lite).


| Event Source | Greengrass nucleus | Greengrass nucleus lite | 
| --- | --- | --- | 
|  Other Lambda functions in the group  |  ✓ (Lambda components and generic components)  |  ✓ (Generic components only)  | 
|  AWS IoT Core service  |  ✓  |  ✓  | 
|  Local shadow service  |  ✓  |  ✗  | 
|  Client device  |  ✓  |  ✗  | 
|  Connector  |  ✓  |  ✗  | 

## Runtime selection decision flow
<a name="runtime-selection-decision-flow"></a>

![\[Decision flow diagram for choosing between Greengrass nucleus and Greengrass nucleus lite.\]](http://docs.aws.amazon.com/greengrass/v2/developerguide/images/runtime-selection-decision-flow.png)


### Notes
<a name="runtime-selection-notes"></a>

1. For Greengrass nucleus lite requirements and compatibility details, see [Greengrass nucleus lite](greengrass-nucleus-lite-component.md). Greengrass nucleus lite requires a minimum of 5 MB RAM and is designed for resource-constrained devices.

1. The decision flow provides guidance based on typical use cases, but is not a strict requirement. Customers with both resource-constrained and resource-sufficient devices may choose to use a single runtime across all devices for operational simplicity, even if some devices could support either runtime.

## Next steps
<a name="next-steps-runtime"></a>

After choosing your runtime, proceed to set up your test device:
+ For Greengrass nucleus runtime: [Set up a new device to test V1 applications on V2](set-up-v2-test-device.md)
+ For Greengrass nucleus lite runtime: [Set up a new device with Greengrass nucleus lite](set-up-v2-test-device-lite.md)

# Set up a new device to test V1 applications on V2
<a name="set-up-test-device"></a>

To minimize risk to your devices in production, create a new device to test your V1 applications on V2 before upgrading your production devices.

Choose one of the following setup guides based on your runtime selection from the previous step:
+ **Option A - Greengrass nucleus runtime**: Follow [Set up a new device to test V1 applications on V2](set-up-v2-test-device.md) if you chose Greengrass nucleus. With this option, you can import Lambda functions as Lambda components with minimal code changes and supports V1 features like local shadow service, client devices, and connectors.
+ **Option B - Greengrass nucleus lite runtime**: Follow [Set up a new device to test V1 applications on V2 (Greengrass nucleus lite)](set-up-v2-test-device-lite.md) if you chose Greengrass nucleus lite. This option requires converting Lambda functions to generic components using the AWS IoT Device SDK V2 or AWS IoT Greengrass Component SDK, but is optimized for resource-constrained devices.

# Set up a new device to test V1 applications on V2
<a name="set-up-v2-test-device"></a>

Set up a new AWS IoT Greengrass V2 core device to deploy and test AWS-provided components and AWS Lambda functions for your AWS IoT Greengrass V1 applications. You can also use this V2 core device to develop and test additional custom Greengrass components that run native processes on core devices. After you test your applications on a V2 core device, you can upgrade your existing V1 core devices to V2 and deploy the V2 components that provide your V1 functionality.



## Step 1: Install AWS IoT Greengrass V2 on a new device
<a name="install-v2-test-device"></a>

Install the AWS IoT Greengrass Core software v2.x on a new device. You can follow the [getting started tutorial](getting-started.md) to set up a device and learn how to develop and deploy components. This tutorial uses [automatic provisioning](quick-installation.md) to quickly set up a device. When you install the AWS IoT Greengrass Core software v2.x, specify the `--deploy-dev-tools` argument to deploy the [Greengrass CLI](greengrass-cli-component.md), so you can develop, test, and debug components directly on the device. For more information about other installation options, including how to install the AWS IoT Greengrass Core software behind a proxy or using a hardware security module (HSM), see [Install the AWS IoT Greengrass Core software](install-greengrass-core-v2.md).

### (Optional) Enable logging to Amazon CloudWatch Logs
<a name="enable-cloudwatch-logging-v2"></a>

To enable a V2 core device to upload logs to Amazon CloudWatch Logs, you can deploy the AWS-provided [log manager component](log-manager-component.md). You can use CloudWatch Logs to view component logs, so you can debug and troubleshoot without access to the core device's file system. For more information, see [Monitor AWS IoT Greengrass logs](monitor-logs.md).

## Step 2: Create and deploy AWS IoT Greengrass V2 components to migrate AWS IoT Greengrass V1 applications
<a name="run-v1-applications"></a>

You can run most AWS IoT Greengrass V1 applications on AWS IoT Greengrass V2. You can import Lambda functions as components that run on AWS IoT Greengrass V2, and you can use [AWS-provided components](public-components.md) that offer the same functionality as AWS IoT Greengrass connectors.

You can also develop custom components to build any feature or runtime to run on Greengrass core devices. For information about how to develop and test components locally, see [Create AWS IoT Greengrass components](create-components.md).

**Topics**
+ [Import V1 Lambda functions](#run-v1-lambda-functions)
+ [Use V1 connectors](#use-v1-connectors)
+ [Run Docker containers](#run-v1-docker-containers)
+ [Connect V1 Greengrass devices](#connect-v1-greengrass-devices)
+ [Enable the local shadow service](#enable-shadow-service)
+ [Integrate with AWS IoT SiteWise](#integrate-with-iot-sitewise)

### Import V1 Lambda functions
<a name="run-v1-lambda-functions"></a>

You can import Lambda functions as AWS IoT Greengrass V2 components. Choose from the following approaches:
+ Import V1 Lambda functions directly as Greengrass components.
+ Update your Lambda functions to use the Greengrass libraries in the AWS IoT Device SDK v2, and then import the Lambda functions as Greengrass components.
+ Create custom components that use non-Lambda code and the AWS IoT Device SDK v2 to implement the same functionality as your Lambda functions.

If your Lambda function uses features, such as stream manager or local secrets, you must define dependencies on the AWS-provided components that package these features. When you deploy the Lambda function component, the deployment also includes the component for each feature that you define as a dependency. In the deployment, you can configure parameters, such as which secrets to deploy to the core device. Not all V1 features require a component dependency for your Lambda function on V2. The following list describes how to use V1 features in your V2 Lambda function component:
+ **Access other AWS services**

  If your Lambda function uses AWS credentials to make requests to other AWS services, the core device's token exchange role must allow the core device to perform the AWS operations that the Lambda function uses. For more information, see [Authorize core devices to interact with AWS services](device-service-role.md).
+ **Stream manager**

  If your Lambda function uses stream manager, specify `aws.greengrass.StreamManager` as a component dependency when you import the function. When you deploy the stream manager component, specify the stream manager parameters to set for the target core devices. The core device's token exchange role must allow the core device to access the AWS Cloud destinations that you use with stream manager. For more information, see [Stream manager](stream-manager-component.md).
+ **Local secrets**

  If your Lambda function uses local secrets, specify `aws.greengrass.SecretManager` as a component dependency when you import the function. When you deploy the secret manager component, specify the secret resources to deploy to the target core devices. The core device's token exchange role must allow the core device to retrieve the secret resources to deploy. For more information, see [Secret manager](secret-manager-component.md).

  When you deploy your Lambda function component, configure it to have an [IPC authorization policy](interprocess-communication.md#ipc-authorization-policies) that grants permission to use the [GetSecretValue IPC operation](ipc-secret-manager.md) in the AWS IoT Device SDK V2.
+ **Local shadows**

  If your Lambda function interacts with local shadows, you must update the Lambda function code to use the AWS IoT Device SDK V2. You must also specify `aws.greengrass.ShadowManager` as a component dependency when you import the function. For more information, see [Interact with device shadows](interact-with-shadows.md).

  When you deploy your Lambda function component, configure it to have an [IPC authorization policy](interprocess-communication.md#ipc-authorization-policies) that grants permission to use the [shadow IPC operations](ipc-local-shadows.md) in the AWS IoT Device SDK V2.
+ **Subscriptions**
  + If your Lambda function subscribes to messages from a cloud source, specify those subscriptions as event sources when you import the function.
  + If your Lambda function subscribes to messages from another Lambda function, or if your Lambda function publishes messages to AWS IoT Core or other Lambda functions, configure and deploy the [legacy subscription router component](legacy-subscription-router-component.md) when you deploy your Lambda function. When you deploy the legacy subscription router component, specify the subscriptions that the Lambda function uses.
**Note**  <a name="legacy-subscription-router-requirement-note"></a>
The legacy subscription router component is required only if your Lambda function uses the `publish()` function in the AWS IoT Greengrass Core SDK. If you update your Lambda function code to use the interprocess communication (IPC) interface in the AWS IoT Device SDK V2, you don't need to deploy the legacy subscription router component. For more information, see the following [interprocess communication](interprocess-communication.md) services:  
[Publish/subscribe local messages](ipc-publish-subscribe.md)
[Publish/subscribe AWS IoT Core MQTT messages](ipc-iot-core-mqtt.md)
  + If your Lambda function subscribes to messages from local connected devices, specify those subscriptions as event sources when you import the function. You must also configure and deploy the [MQTT bridge component](mqtt-bridge-component.md) to relay messages from the connected devices to the local publish/subscribe topics that you specify as event sources.
  + If your Lambda function publishes messages to local connected devices, you must update the Lambda function code to use the AWS IoT Device SDK V2 to [publish local publish/subscribe messages](ipc-publish-subscribe.md). You must also configure and deploy the [MQTT bridge component](mqtt-bridge-component.md) to relay messages from the local publish/subscribe message broker to the connected devices.
+ **Local volumes and devices**

  If your containerized Lambda function accesses local volumes or devices, specify those volumes and devices when you import the Lambda function. This feature doesn't require a component dependency.

For more information, see [Run AWS Lambda functions](run-lambda-functions.md).

### Use V1 connectors
<a name="use-v1-connectors"></a>

You can deploy AWS-provided components that offer the same functionality of some AWS IoT Greengrass connectors. When you create the deployment, you can configure the connectors' parameters. 

The following AWS IoT Greengrass V2 components provide Greengrass V1 connector functionality:
+ [CloudWatch metrics component](cloudwatch-metrics-component.md)
+ [AWS IoT Device Defender component](device-defender-component.md)
+ [Firehose component](kinesis-firehose-component.md)
+ [Modbus-RTU protocol adapter component](modbus-rtu-protocol-adapter-component.md)
+ [Amazon SNS component](sns-component.md)

### Run Docker containers
<a name="run-v1-docker-containers"></a>

AWS IoT Greengrass V2 doesn't provide a component to directly replace the V1 Docker application deployment connector. However, you can use the Docker application manager component to download Docker images, and then create custom components that run Docker containers from the downloaded images. For more information, see [Run a Docker container](run-docker-container.md) and [Docker application manager](docker-application-manager-component.md).

### Connect V1 Greengrass devices
<a name="connect-v1-greengrass-devices"></a>

Connected devices in AWS IoT Greengrass V1 are called client devices in AWS IoT Greengrass V2. AWS IoT Greengrass V2 support for client devices is backward-compatible with AWS IoT Greengrass V1, so you can connect V1 client devices to V2 core devices without changing their application code. To enable client devices to connect to a V2 core device, deploy Greengrass components that enable client device support, and associate the client devices to the core device. To relay messages between client devices, the AWS IoT Core cloud service, and Greengrass components (including Lambda functions), deploy and configure the [MQTT bridge component](mqtt-bridge-component.md). You can deploy the [IP detector component](ip-detector-component.md) to automatically detect connectivity information, or you can manually manage endpoints. For more information, see [Interact with local IoT devices](interact-with-local-iot-devices.md).

### Enable the local shadow service
<a name="enable-shadow-service"></a>

In AWS IoT Greengrass V2, the local shadow service is implemented by the AWS-provided shadow manager component. AWS IoT Greengrass V2 also includes support for named shadows. To enable your components to interact with local shadows and to sync shadow states to AWS IoT Core, configure and deploy the shadow manager component, and use the shadow IPC operations in your component code. For more information, see [Interact with device shadows](interact-with-shadows.md). 

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

If you use your V1 core device as an AWS IoT SiteWise gateway, [follow instructions](https://docs.aws.amazon.com/iot-sitewise/latest/userguide/configure-gateway-ggv2.html) to set up your new V2 core device as an AWS IoT SiteWise gateway. AWS IoT SiteWise provides an installation script that deploys the AWS IoT SiteWise components for you.

## Step 3: Test your AWS IoT Greengrass V2 applications
<a name="test-v2-features"></a>

After you create and deploy V2 components to your new V2 core device, verify that your applications meet your expectations. You can check the device's logs to view your components' standard output (stdout) and standard error (stderr) messages. For more information, see [Monitor AWS IoT Greengrass logs](monitor-logs.md).

If you deployed the [Greengrass CLI](greengrass-cli-component.md) to the core device, you can use it to debug components and their configurations. For more information, see [Greengrass CLI commands](gg-cli-reference.md).

After you verify that your applications work on a V2 core device, you can deploy your application's Greengrass components to other core devices. If you developed custom components that run native processes or Docker containers, you must first [publish those components](publish-components.md) to the AWS IoT Greengrass service to deploy them to other core devices.

# Set up a new device to test V1 applications on V2 (Greengrass nucleus lite)
<a name="set-up-v2-test-device-lite"></a>

Set up a new device with Greengrass nucleus lite to test generic components that you create to migrate your AWS IoT Greengrass V1 applications to V2. Greengrass nucleus lite is a lightweight runtime optimized for resource-constrained devices. You can use this device to develop and test custom Greengrass components that run native processes. After you test your applications on a Greengrass nucleus lite device, you can deploy the V2 components to other devices running Greengrass nucleus lite or upgrade your existing V1 core devices to V2.



## Step 1: Install Greengrass nucleus lite on a new device
<a name="lite-step-1-install"></a>

Install the Greengrass nucleus lite on a new device. Follow the [Greengrass nucleus lite installation guide](https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-nucleus-lite-component.html#greengrass-nucleus-lite-component-install) to set up a device.

**Note**  
Greengrass nucleus lite does not support local shadow service, client devices, or connectors now. Ensure your V1 applications don't rely on these features before proceeding with this guide.

## Step 2: Create and deploy generic components to migrate AWS IoT Greengrass V1 Lambda functions
<a name="lite-step-2-convert-lambda"></a>

To replicate the functionality of your AWS IoT Greengrass V1 Lambda functions on Greengrass nucleus lite, you must convert them to generic components. This involves rewriting your Lambda function code to use the AWS IoT Device SDK V2 or AWS IoT Greengrass Component SDK instead of the AWS IoT Greengrass Core SDK.

The following table lists the SDKs used in the V2 component examples in this guide:


| SDK | Minimum version | 
| --- | --- | 
| [AWS IoT Device SDK for Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2) | v1.11.3 | 
| [AWS IoT Device SDK for Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2) | v1.9.3 | 
| [AWS IoT Device SDK for JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2) | v1.12.0 | 
| [AWS IoT Greengrass Component SDK (C/C\$1\$1)](https://github.com/aws-greengrass/aws-greengrass-component-sdk) (currently in preview) | v0.4.0 | 

Below examples show Lambda functions that use the AWS IoT Greengrass V1 Core SDK and their equivalent generic components, with component code, recipes, and build instructions in multiple programming languages for two main scenarios:
+ **Local communication** - Components that communicate with other components on the same device using local pub/sub
+ **Cloud communication** - Components that communicate with AWS IoT Core or other AWS services

### Scenario 1: Local Communication (publisher → processor → subscriber)
<a name="lite-example-local-communication"></a>

This scenario demonstrates converting a V1 Lambda function that uses local pub/sub communication to a V2 generic component.

#### Application architecture
<a name="lite-example-1-scenario"></a>

This example involves three components:
+ Publisher Lambda publishes temperature data
+ Processor Lambda receives data and processes it
+ Processor Lambda publishes processed result to subscriber Lambda

The code example below focuses on the processor Lambda, which demonstrates both subscribing to and publishing messages for local communication.

##### V1 group subscriptions
<a name="lite-example-1-v1-subscriptions"></a>

In AWS IoT Greengrass V1, the following group subscriptions enable communication between Lambda functions:

Subscription 1: publisher → processor
+ Source: Lambda (publisher)
+ Target: Lambda (processor)
+ Topic: sensors/temperature

Subscription 2: processor → subscriber
+ Source: Lambda (processor)
+ Target: Lambda (subscriber)
+ Topic: lambda/alerts

#### Processor Lambda function (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;
}
```

------

#### Generic component (V2)
<a name="lite-example-1-v2-code"></a>

To achieve the same functionality in AWS IoT Greengrass V2, create a generic component with the following:

##### 1. Component code
<a name="lite-example-1-component-code"></a>

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

Prerequisites: Before using this component code, install and verify the AWS IoT Device SDK for Python on your Greengrass device:

```
# Install the SDK
pip3 install awsiotsdk

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

If you encounter dependency conflicts during installation, try installing a specific version of the AWS IoT Device SDK.

If the verification command prints "SDK installed successfully", you're ready to use the component code:

```
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. Build and package the component
<a name="lite-example-1-build-component"></a>

Some languages require building or packaging before deployment.

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

Python does not require compilation. The component can use the .py file directly.

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

To build an executable JAR with all dependencies bundled:

1. Create a `pom.xml` file in your project directory:

   ```
   <?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. Build the JAR:

   ```
   mvn clean package
   ```

   This creates `target/temperature-processor-1.0.0.jar` with all dependencies included.

1. Upload the JAR to your S3 bucket for deployment.

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

To package your Node.js component with all dependencies:

1. Create a `package.json` file:

   ```
   {
     "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. Install dependencies on your development machine:

   ```
   npm install
   ```

   This creates a `node_modules` folder containing the AWS AWS IoT Device SDK v2.

1. Package for deployment:

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

1. Upload the zip file to your S3 bucket for deployment.

**Note**  
The Greengrass device must have Node.js runtime installed (version 14 or later). You don't need to run `npm install` on the Greengrass core device since the component artifact includes all dependencies in the bundled `node_modules` folder.

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

**Prerequisites:**

To build the SDK and the component, you will need the following build dependencies:
+ GCC or Clang
+ CMake (at least version 3.22)
+ Make or Ninja

**Install build dependencies:**

On Ubuntu/Debian:

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

On Amazon Linux:

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

**Create a CMakeLists.txt file for your component:**

```
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)
```

**Build steps:**

```
# 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 ]

**Prerequisites:**

To build the SDK and the component, you will need the following build dependencies:
+ GCC or Clang with C\$1\$120 support
+ CMake (at least version 3.22)
+ Make or Ninja

**Install build dependencies:**

On Ubuntu/Debian:

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

On Amazon Linux:

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

**Create a CMakeLists.txt file for your component:**

```
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++)
```

**Build steps:**

```
# 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. Component recipe
<a name="lite-example-1-component-recipe"></a>

Update the "resources" array with the actual topics your component uses.

------
#### [ 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"
        }
      ]
    }
  ]
}
```

------

### Scenario 2: Cloud Communication
<a name="lite-example-cloud-communication"></a>

This scenario demonstrates converting a V1 Lambda function that communicates with AWS IoT Core to a V2 generic component.

#### Application architecture
<a name="lite-example-2-scenario"></a>

This example uses a cloud-connected architecture:
+ AWS IoT Core sends commands to the device
+ Controller Lambda receives commands and processes them
+ Controller Lambda sends telemetry data back to AWS IoT Core

This example focuses on the controller Lambda, which demonstrates both receiving messages from and publishing messages to AWS IoT Core.

##### V1 group subscriptions
<a name="lite-example-2-v1-subscriptions"></a>

In AWS IoT Greengrass V1, the following group subscriptions enable communication between the Lambda function and AWS IoT Core:

Subscription 1: IoT Cloud → Lambda
+ Source: IoT Cloud
+ Target: Lambda (DeviceController)
+ Topic: commands/device1

Subscription 2: Lambda → IoT Cloud
+ Source: Lambda (DeviceController)
+ Target: IoT Cloud
+ Topic: telemetry/device1

#### Controller Lambda function (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;
}
```

------

#### Generic component (V2)
<a name="lite-example-2-v2-code"></a>

To achieve the same functionality in AWS IoT Greengrass V2, create a generic component with the following:

##### 1. Component code
<a name="lite-example-2-component-code"></a>

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

Prerequisites: Before using this component code, install and verify the AWS IoT Device SDK for Python on your Greengrass device:

```
# Install the SDK
pip3 install awsiotsdk

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

If you encounter dependency conflicts during installation, try installing a specific version of the AWS IoT Device SDK.

If the verification command prints "SDK installed successfully", you're ready to use the component code:

```
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. Build and package the component
<a name="lite-example-2-build-component"></a>

Some languages require building or packaging before deployment.

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

Python does not require compilation. The component can use the .py file directly.

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

To build an executable JAR with all dependencies bundled:

1. Create a `pom.xml` file in your project directory:

   ```
   <?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. Build the JAR:

   ```
   mvn clean package
   ```

   This creates `target/device-controller-1.0.0.jar` with all dependencies included.

1. Upload the JAR to your S3 bucket for deployment.

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

To package your Node.js component with all dependencies:

1. Create a `package.json` file:

   ```
   {
     "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. Install dependencies on your development machine:

   ```
   npm install
   ```

   This creates a `node_modules` folder containing the AWS AWS IoT Device SDK v2.

1. Package for deployment:

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

1. Upload the zip file to your S3 bucket for deployment.

**Note**  
The Greengrass device must have Node.js runtime installed (version 14 or later). You don't need to run `npm install` on the Greengrass core device since the component artifact includes all dependencies in the bundled `node_modules` folder.

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

**Prerequisites:**

To build the SDK and the component, you will need the following build dependencies:
+ GCC or Clang
+ CMake (at least version 3.22)
+ Make or Ninja

**Install build dependencies:**

On Ubuntu/Debian:

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

On Amazon Linux:

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

**Create a CMakeLists.txt file for your component:**

```
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)
```

**Build steps:**

```
# 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 ]

**Prerequisites:**

To build the SDK and the component, you will need the following build dependencies:
+ GCC or Clang with C\$1\$120 support
+ CMake (at least version 3.22)
+ Make or Ninja

**Install build dependencies:**

On Ubuntu/Debian:

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

On Amazon Linux:

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

**Create a CMakeLists.txt file for your component:**

```
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++)
```

**Build steps:**

```
# 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. Component recipe
<a name="lite-example-2-component-recipe"></a>

Update the "resources" array with the actual topics your component uses.

------
#### [ 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"
        }
      ]
    }
  ]
}
```

------

# Upgrade Greengrass V1 core devices to Greengrass V2
<a name="upgrade-v1-core-devices"></a>

After you verify that your applications and components work on an AWS IoT Greengrass V2 core device, you can install the AWS IoT Greengrass Core software v2.x on your devices that currently run v1.x, such as production devices. Then, deploy Greengrass V2 components to run your Greengrass applications on the devices.

To upgrade a fleet of devices from V1 to V2, complete these steps for each device to upgrade. You can use thing groups to deploy V2 components to a fleet of core devices.

**Tip**  
We recommend that you create a script to automate the upgrade process for a fleet of devices. If you use [AWS Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/what-is-systems-manager.html) to manage your fleet, you can use Systems Manager to run that script on each device to upgrade your fleet from V1 to V2.  
You can contact your AWS Enterprise Support representative with questions about how to best automate the upgrade process.



## Step 1: Install the AWS IoT Greengrass Core software v2.x
<a name="install-v2-on-v1"></a>

Choose from the following options to install the AWS IoT Greengrass Core software v2.x on a V1 core device:
+ **[Upgrade in fewer steps](#install-v2-after-uninstall)**

  To upgrade in fewer steps, you can uninstall the v1.x software before you install the v2.x software.
+ **[Upgrade with minimal downtime](#install-v2-side-by-side)**

  To upgrade with minimal downtime, you can install both versions of the AWS IoT Greengrass Core software at the same time. After you install the AWS IoT Greengrass Core software v2.x and verify that your V2 applications operate correctly, you uninstall the AWS IoT Greengrass Core software v1.x. Before you choose this option, consider the additional RAM required to run both versions of the AWS IoT Greengrass Core software at the same time.

### Uninstall AWS IoT Greengrass Core v1.x before you install v2.x
<a name="install-v2-after-uninstall"></a>

If you want to upgrade sequentially, uninstall the AWS IoT Greengrass Core software v1.x before you install v2.x on your device.

**To uninstall the AWS IoT Greengrass Core software v1.x**

1. If the AWS IoT Greengrass Core software v1.x is running as a service, you must stop, disable, and remove the service.

   1. Stop the running AWS IoT Greengrass Core software v1.x service. 

      ```
      sudo systemctl stop greengrass 
      ```

   1. Wait until the service stops. You can use the `list` command to check the status of the service. 

      ```
      sudo systemctl list-units --type=service | grep greengrass
      ```

   1. Disable the service. 

      ```
      sudo systemctl disable greengrass
      ```

   1. Remove the service. 

      ```
      sudo rm /etc/systemd/system/greengrass.service
      ```

1. If the AWS IoT Greengrass Core software v1.x is not running as a service, use the following command to stop the daemon. Replace *greengrass-root* with the name of your Greengrass root folder. The default location is `/greengrass`.

   ```
   cd /greengrass-root/ggc/core/
   sudo ./greengrassd stop
   ```

1. (Optional) Back up your Greengrass root folder and, if applicable, your [custom write folder](https://docs.aws.amazon.com/greengrass/v1/developerguide/gg-core.html#write-directory), to a different folder on your device.

   1. Use the following command to copy the current Greengrass root folder to a different folder, and then remove the root folder.

      ```
      sudo cp -r /greengrass-root /path/to/greengrass-backup
      rm -rf /greengrass-root
      ```

   1. Use the following command to move the write folder to a different folder, and then remove the write folder. 

      ```
      sudo cp -r /write-directory /path/to/write-directory-backup
      rm -rf /write-directory
      ```

For Greengrass nucleus: You can use the [installation instructions for AWS IoT Greengrass V2](install-greengrass-core-v2.md) to install the Greengrass nucleus on your device.

For Greengrass nucleus lite: You can use the [installation instructions for Greengrass nucleus lite](greengrass-nucleus-lite-component.md) to install Greengrass nucleus lite.

**Tip**  <a name="tip-migrate-reuse-core-device-identity"></a>
To reuse a core device's identity when you migrate it from V1 to V2, follow instructions to [install the AWS IoT Greengrass Core software with manual provisioning](manual-installation.md). First remove the V1 core software from the device, and then reuse the V1 core device's AWS IoT thing and certificate, and update the certificate's AWS IoT policies to grant permissions that the v2.x software requires.

### Install AWS IoT Greengrass Core software v2.x on a device already running v1.x
<a name="install-v2-side-by-side"></a>

If you install the AWS IoT Greengrass Core v2.x software on a device that is already running the AWS IoT Greengrass Core software v1.x, keep the following in mind:
+ The AWS IoT thing name for your V2 core device must be unique. Don't use the same thing name as your V1 core device.
+ The ports that you use for the AWS IoT Greengrass Core software v2.x must be different from the ports that you use for v1.x.
  + Configure the V1 stream manager to use a port other than 8088. For more information, see [Configure stream manager](https://docs.aws.amazon.com/greengrass/v1/developerguide/configure-stream-manager.html).
  + Configure the V1 MQTT broker to use a port other than 8883. For more information, see [Configure the MQTT port for local messaging](https://docs.aws.amazon.com/greengrass/v1/developerguide/gg-core.html#config-local-mqtt-port).
+ AWS IoT Greengrass V2 doesn't provide the option to rename the Greengrass system service. If you run Greengrass as a system service, you must do one of the following to avoid conflicting system service names:
  + Rename the Greengrass service for v1.x before you install v2.x.
  + Install the AWS IoT Greengrass Core software v2.x without a system service, and then manually [configure the software as a system service](configure-greengrass-core-v2.md#configure-system-service) with a name other than `greengrass`.

**To rename the Greengrass service for v1.x**

  1. Stop the AWS IoT Greengrass Core software v1.x service. 

     ```
     sudo systemctl stop greengrass
     ```

  1. Wait for the service to stop. The service can take up to a few minutes to stop. You can use the `list-units` command to check whether the service stopped. 

     ```
     sudo systemctl list-units --type=service | grep greengrass
     ```

  1. Disable the service. 

     ```
     sudo systemctl disable greengrass
     ```

  1. Rename the service. 

     ```
     sudo mv /etc/systemd/system/greengrass.service /etc/systemd/system/greengrass-v1.service
     ```

  1. Reload the service and start it. 

     ```
     sudo systemctl daemon-reload
     sudo systemctl reset-failed
     sudo systemctl enable greengrass-v1 
     sudo systemctl start greengrass-v1
     ```

You can then use the [installation instructions for AWS IoT Greengrass V2](install-greengrass-core-v2.md) to install the software on your device.

**Tip**  <a name="tip-migrate-reuse-core-device-identity"></a>
To reuse a core device's identity when you migrate it from V1 to V2, follow instructions to [install the AWS IoT Greengrass Core software with manual provisioning](manual-installation.md). First remove the V1 core software from the device, and then reuse the V1 core device's AWS IoT thing and certificate, and update the certificate's AWS IoT policies to grant permissions that the v2.x software requires.

## Step 2: Deploy AWS IoT Greengrass V2 components to the core devices
<a name="deploy-v2-resources"></a>

After you install the AWS IoT Greengrass Core software v2.x on your device, deploy components based on which runtime you chose.

### For Greengrass nucleus:
<a name="deploy-nucleus-components"></a>

Create a deployment that includes the following resources. To deploy components to a fleet of similar devices, create a deployment for a thing group that contains those devices.
+ Lambda function components that you created from your V1 Lambda functions. For more information, see [Run AWS Lambda functions](run-lambda-functions.md).
+ If you use V1 subscriptions, the [legacy subscription router component](legacy-subscription-router-component.md).
+ If you use stream manager, the [stream manager component](stream-manager-component.md). For more information, see [Manage data streams on Greengrass core devices](manage-data-streams.md).
+ If you use local secrets, the [secret manager component](secret-manager-component.md).
+ If you use V1 connectors, the [AWS-provided connector components](set-up-v2-test-device.md#use-v1-connectors).
+ If you use Docker containers, the [Docker application manager component](docker-application-manager-component.md). For more information, see [Run a Docker container](run-docker-container.md).
+ If you use connected devices, the [components for client device support](client-device-components.md). You must also enable client device support and associate the client devices with your core device. For more information, see [Interact with local IoT devices](interact-with-local-iot-devices.md).
+ If you use device shadows, the [shadow manager component](shadow-manager-component.md). For more information, see [Interact with device shadows](interact-with-shadows.md).
+ If you upload logs from Greengrass core devices to Amazon CloudWatch Logs, the [log manager component](log-manager-component.md). For more information, see [Monitor AWS IoT Greengrass logs](monitor-logs.md).
+ If you integrate with AWS IoT SiteWise, [follow instructions](https://docs.aws.amazon.com/iot-sitewise/latest/userguide/configure-gateway-ggv2.html) to set up the V2 core device as an AWS IoT SiteWise gateway. AWS IoT SiteWise provides an installation script that deploys the AWS IoT SiteWise components for you.
+ User-defined components that you developed to implement custom functionality.

For information about creating and revising deployments, see [Deploy AWS IoT Greengrass components to devices](manage-deployments.md). 

### For Greengrass nucleus lite:
<a name="deploy-nucleus-lite-components"></a>

Deploy the generic components you created in [Step 2 of the migration guide](set-up-v2-test-device-lite.md#lite-step-2-convert-lambda) to your Greengrass nucleus lite devices:

1. Create your components in using the component recipes you created

1. Create a deployment targeting your Greengrass nucleus lite devices that includes your generic components

1. Verify that your components are running correctly