Getting started with AWS IoT Greengrass and C# .NET development
Tags: greengrass, iot
Published: 2023-01-19 15:32:39

## Introduction

AWS IoT Greengrass is a powerful tool for creating and deploying IoT software components to devices, allowing you to perform tasks such as data processing, analytics, and device control, orchestrating all of this from the cloud. This can be especially useful for IoT systems that need to operate in low-bandwidth or offline environments but also want to re-use existing software stacks and make sure they are up to date while allowing new functionality to be added as well.

While there are examples for developers using C/C++, Java and Python to develop components that utilize the Greengrass Inter-Process Communication (IPC) features to interface with the cloud, C# .NET is not officially supported in the device SDK to interface with the Greengrass IPC. This means that developers using C# .NET cannot take advantage of the benefits of developing components using C#, thus limit the access to a large number of pre-existing libraries and a large developer community.

However, it's still possible to develop Greengrass components using C# .NET by using EventStream for Greengrass IPC. In this post, we'll walk through an example of developing an AWS IoT Greengrass component using C# .NET on Linux development machine. We will be showing you how to set up the development environment, how to develop the component, and how to deploy it to a Greengrass device, where this component will be publishing to AWS IoT Core current process information.

## Prerequisites

For this example, we'll be using a development machine with the following software installed:

* .NET Core SDK 6.0+
* Visual Studio Code with the C# extension installed
* An AWS account and AWS IoT Greengrass provisioned on a compatible device. For more info take a look at the [Getting Started](https://docs.aws.amazon.com/greengrass/v2/developerguide/getting-started.html). 
* [Greengrass Development Kit CLI](https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-development-kit-cli.html) 

## Setting up the Development Environment

The example is a located under [greeneyes](https://github.com/aws-iot-builder-tools/greeneyes/tree/main/blog-posts/002) repository, which will utilise some of the scripts introduced in order to make easier development. For more details take a look at the initial [blog](https://aws.amazon.com/blogs/iot/build-an-efficient-development-environment-for-aws-iot-greengrass/).

That being said, let’s checkout the repository with the command:

```
git clone git@github.com:aws-iot-builder-tools/greeneyes.git
```

Next, we'll proceed to our C# example located under `greeneyes/blog-posts/002/shared/CSharpExample` , and explore the code. The part which adds the IPC communication between the Greengrass component and the Greengrass Nucleus can be found under `Events` directory, while the main program is in the `Program.cs` .

## Developing the Greengrass Component

Now we're ready to start looking at our Greengrass component. Let's open the project in Visual Studio Code using the following command :

```
code .
```

In the `Program.cs` file, we can see our `Main` function and change it to suit our needs. In this example, we have a main loop that publishes current process information representing our Greengrass device to a topic `greengrass/[AWS_IOT_THING_NAME]` where `AWS_IOT_THING_NAME` will be retrieved from a an environment set by the Greeengrass Nucleus.

```
using System;
using System.Diagnostics;
using System.Threading;

namespace GGCSharp
{
    public static class Program
    {
        public static bool Running { get; set; } = true;
        private static string AwsIotThingName => Environment.GetEnvironmentVariable("AWS_IOT_THING_NAME");
        public static string ThingTopic => string.Join("/", "greengrass", AwsIotThingName);

        private static void Main(string[] args)
        {
            InstallShutdownHandler();

            while (Running)
            {
                var currentProcess = Process.GetCurrentProcess();
                AwsIotGreengrassIpc.Publish(ThingTopic, 0, $"Hello from C# process: {currentProcess.WorkingSet64}");
                Thread.Sleep(10000);
            }

            AwsIotGreengrassIpc.Publish(ThingTopic, 1, "Shutting down");
        }

        private static void InstallShutdownHandler()
        {
            // If the process is exiting set the global running flag to false
            AppDomain.CurrentDomain.ProcessExit += (_, _) => Running = false;
        }
    }
}
```

The Main method also calls a method named "InstallShutdownHandler" which is attaching an event handler to the "ProcessExit" event of the current app domain. The event handler is just a lambda that sets the Running variable to false, which stops the infinite loop and sends a last message "Shutting down" on the topic with a qos=1 before the program exits.

## Deploying the Greengrass Component

Once our code is complete, we can deploy it to our Greengrass device. We need to create a deployment package containing our code, by running the following commands in the terminal:

```
dotnet publish -c Release
```

This will fetch the necessary dependencies, create a release build of the project and create a deployment package in the bin/Release/net6.0/publish directory. Now we can build the Greengrass artifact:

```
mkdir -p greengrass-build/artifacts/greeneyes.GGCSharp/NEXT_PATCH
pushd .
cd bin/Release/net6.0/publish
zip -r -X GGCSharp.zip .
popd
mv bin/Release/net6.0/publish/GGCSharp.zip greengrass-build/artifacts/greeneyes.GGCSharp/NEXT_PATCH
```

The above commands will create a directory structure for the Greengrass component artifact, zip the build and move it.

Before we generate an appropriate component recipe we first need to make sure we have a correct `gdk-config.json` as we will be using [Greengrass Development Kit CLI](https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-development-kit-cli.html) for the deployment.

Here we have a `gdk-config.json.template` file where we need to modify: author, bucket and region and save it as a `gdk-config.json`

```
{
  "component": {
    "greeneyes.GGCSharp": {
      "author": "<PLACEHOLDER_AUTHOR>",
      "version": "NEXT_PATCH",
      "build": {
        "build_system": "custom",
        "custom_build_command": [ "./build.sh" ]
      },
      "publish": {
        "bucket": "<PLACEHOLDER_BUCKET>",
        "region": "<PLACEHOLDER_REGION>"
      }
    }
  },
  "gdk_version": "1.0.0"
}
```

For author we can simply put *BlogReader*, but for s3 bucket and region we can use AWS CLI to populate those.
For example for region we can use:

```
aws configure get region
```

and replace the output, and for the bucket we suggest creating a unique bucket that is related to the project. For example taking the hostname and machine-id:

```
echo $(sed 's/-//g' <<< $(hostname))$(head -c 8 /etc/machine-id)
```

Next we can move to the component recipe:

```
---
RecipeFormatVersion: "2020-01-25"
ComponentName: "{COMPONENT_NAME}"
ComponentVersion: "{COMPONENT_VERSION}"
ComponentDescription: "This is simple Hello World component written in C#."
ComponentPublisher: "{COMPONENT_AUTHOR}"
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        "mqtt:1":
          operations:
            - "aws.greengrass#PublishToIoTCore"
          resources:
            - "*"
ComponentDependencies:
  aws.greengrass.TokenExchangeService:
    VersionRequirement: '^2.0.0'
    DependencyType: HARD
Manifests:
  - Platform:
      os: all
    Artifacts:
      - URI: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/GGCSharp.zip"
        Unarchive: ZIP
    Lifecycle:
      Run: "chmod +x {artifacts:decompressedPath}/GGCSharp/GGCSharp && {artifacts:decompressedPath}/GGCSharp/GGCSharp"
```

Where we need to make sure we update the `{COMPONENT_NAME}` and `{COMPONENT_AUTHOR}` respectively, after moving the recipe to the `greengrass-build` directory.

```
mkdir -p greengrass-build/recipes
cp recipe.yaml greengrass-build/recipes/recipe.yaml
```

Once finished we can then simply use the gdk tool to build and publish the our Greengrass component:

```
gdk component build
gdk component publish
```

In order to make this easer a `build.sh` script with the same instructions is located in the root folder of the example.

Once the component is created we can simply go to the AWS Console under AWS IoT → Greengrass → Deployments and create a deployment to target our desired device and go through a process of deploying our component, or just using the command:

```
aws greengrassv2 create-deployment \
          --cli-input-json file://deployment.json \
          --region ${AWS_REGION}
```

 where the deployment.json could look something like this:

```
{
    "targetArn": "arn:aws:iot:$AWS_REGION:$AWS_ACCOUNT_ID:thinggroup/<Thing Group>",
    "deploymentName": "Deployment for our group",
    "components": {
        "<COMPONENT_NAME>": {
            "componentVersion": "$LATEST_COMPONENT_VERSION",
            "runWith": {}
        },
        "aws.greengrass.Nucleus": {
            "componentVersion": "2.8.1"
        }
    },
    "deploymentPolicies": {
        "failureHandlingPolicy": "ROLLBACK",
        "componentUpdatePolicy": {
            "timeoutInSeconds": 60,
            "action": "NOTIFY_COMPONENTS"
        },
        "configurationValidationPolicy": {
            "timeoutInSeconds": 60
        }
    },
    "iotJobConfiguration": {}
}
```

Alternatively we can use our project helper tools to deploy the component by simply executing:

```
gg-cloud-deploy
```

which should do all the steps above. 

### Viewing Publishing Data

Once the component is deployed and running we can should be able to see the incoming data by going to AWs IoT → MQTT test client and subscribing to a topic `greengrass/[AWS_IOT_THING_NAME]`

![MQTT Test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fphoqi3jujdxazka6oyp.png)

## Limitations

Currently, the only available method for IPC is `PublishToIotCore`. However, other methods can be implemented by referencing the APIs provided in the python SDK, located a [here](https://github.com/aws/aws-iot-device-sdk-python-v2/blob/main/awsiot/greengrasscoreipc/model.py#L6337). In the future, we aim to integrate these methods directly into our `RpcMessages.cs` for greater convenience.

## Conclusion

In this post, we've walked through an example of developing an AWS IoT Greengrass component using C# .NET. We've seen how to set up the development environment, write the code for the component, and deploy it to a Greengrass device. With the power of C# and the AWS IoT Greengrass, you can easily create powerful and robust Greengrass components for IoT devices. We acknowledge that there are limitations in interfacing the IPC, but per need bases this can be extended. We did not cover the methods for interacting with other AWS cloud services in this discussion, however it is possible to do so by utilizing the C# SDK as outlined in the documentation provided at [here](https://docs.aws.amazon.com/greengrass/v2/developerguide/interact-with-aws-services.html).

Please reach out if you have any questions or need help with your development, we're always happy to help.