<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nenad Ilic</title>
    <description>The latest articles on DEV Community by Nenad Ilic (@nenadilic84).</description>
    <link>https://dev.to/nenadilic84</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F956175%2F33ad175e-943e-488c-a7fd-7fbe15a02604.jpeg</url>
      <title>DEV Community: Nenad Ilic</title>
      <link>https://dev.to/nenadilic84</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nenadilic84"/>
    <language>en</language>
    <item>
      <title>Developing Your First Greengrass Publish Component on Raspberry Pi</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Thu, 20 Jul 2023 14:13:19 +0000</pubDate>
      <link>https://dev.to/iotbuilders/developing-your-first-greengrass-publish-component-on-raspberry-pi-3fg4</link>
      <guid>https://dev.to/iotbuilders/developing-your-first-greengrass-publish-component-on-raspberry-pi-3fg4</guid>
      <description>&lt;p&gt;In the &lt;a href="https://dev.to/iotbuilders/aws-iot-greengrass-components-deployment-with-gdk-using-github-actions-245m"&gt;previous blog post&lt;/a&gt;, we delved into the world of AWS IoT Greengrass V2, focusing on the usage of the Greengrass Development Kit (GDK) and how it can be automated with GitHub Actions. Today, we're going to take it a step further. We'll walk through the process of developing your first AWS IoT Greengrass Publish component on a Raspberry Pi.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Setting Up Your Environment
&lt;/h2&gt;

&lt;p&gt;Before we start, ensure that you have your Raspberry Pi is set up by using the &lt;a href="https://dev.to/iotbuilders/fleet-provisioning-for-embedded-linux-devices-with-aws-iot-greengrass-4h8b"&gt;Fleet Provisioning mehtod&lt;/a&gt; as we will be using now those GitHub Actions and the project we created in our previous blog post to deploy our component. In scenarios that you are working with a different OS, you would need to follow the instruction on &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/quick-installation.html"&gt;installing AWS IoT Greengrass&lt;/a&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Designing the Message Publisher Component
&lt;/h2&gt;

&lt;p&gt;The first step in creating our messaging system is to create the message publisher component. This component will be responsible for sending data, such as sensor readings or application logs, to a specified topic. &lt;/p&gt;

&lt;p&gt;In the AWS IoT Greengrass, components are defined by a recipe, which is a JSON or YAML file that specifies the component's metadata, lifecycle, configuration, and dependencies. For our message publisher component, we'll need to define a recipe that includes the necessary AWS IoT Greengrass component to publish messages to a topic.&lt;/p&gt;

&lt;p&gt;Here's an example of what the recipe might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
RecipeFormatVersion: "2020-01-25"
ComponentName: "{COMPONENT_NAME}"
ComponentVersion: "{COMPONENT_VERSION}"
ComponentDescription: "A component that publishes temperature data to AWS IoT Core"
ComponentPublisher: "{COMPONENT_AUTHOR}"
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        'com.example.pub:mqttproxy:1':
          policyDescription: Allows access to publish the temperature to topic.
          operations:
            - aws.greengrass#PublishToTopic
          resources:
            - 'CPU/info'
Manifests:
  - Platform:
      os: all
    Artifacts:
      - URI: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/com.example.pub.zip"
        Unarchive: ZIP
    Lifecycle:
      Run: "python3 -u {artifacts:decompressedPath}/com.example.pub/main.py"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this recipe, we're creating a component with the name &lt;code&gt;com.example.pub&lt;/code&gt;. This component is different from our previous examples due to the inclusion of an &lt;code&gt;accessControl:&lt;/code&gt; configuration. This configuration allows the component to publish messages to a specific MQTT topic.&lt;/p&gt;

&lt;p&gt;In our case, the &lt;code&gt;resource&lt;/code&gt; is set to &lt;code&gt;CPU/info&lt;/code&gt;. This setting means that our component has permission to publish only to the &lt;code&gt;CPU/info&lt;/code&gt; MQTT topic. &lt;/p&gt;

&lt;p&gt;If you need the component to publish to multiple topics, you can extend the list of &lt;code&gt;resources&lt;/code&gt; with additional topic names. Alternatively, if you want the component to have permission to publish to any topic, you can replace &lt;code&gt;CPU/info&lt;/code&gt; with &lt;code&gt;*&lt;/code&gt;. This wildcard character represents all possible topics, granting the component full publishing access. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Implementing the Message Publisher Component
&lt;/h2&gt;

&lt;p&gt;With the component designed, we can now move on to implementing the message publisher component. This involves writing the &lt;code&gt;main.py&lt;/code&gt; script that we referenced in the component recipe.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;main.py&lt;/code&gt; script will use the AWS SDK for Python which uses &lt;code&gt;awsiot.greengrasscoreipc.clientv2&lt;/code&gt; to interact with Greengrass IPC in order to publish messages to a specified AWS IoT topic. Here's an example of what the script would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
import time
import json
import awsiot.greengrasscoreipc.clientv2 as clientV2

TOPIC="CPU/info"

def get_cpu_temp():
    temp_file = open("/sys/class/thermal/thermal_zone0/temp")
    cpu_temp = temp_file.read()
    temp_file.close()
    return float(cpu_temp)/1000

def main():
    # Create an IPC client.
    ipc_client = clientV2.GreengrassCoreIPCClientV2()

    while True:
        cpu_temp = get_cpu_temp()
        print("CPU temperature: {:.2f} C".format(cpu_temp))

        # Create a payload.
        payload = json.dumps({"temperature": cpu_temp})

        # Publish the payload to AWS IoT Core.
        resp = ipc_client.publish_to_iot_core(topic_name=TOPIC, qos="1", payload=payload)

        time.sleep(1)  # sleep for 1 second

    ipc_client.close()

if __name__ == "__main__":
    main()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this script, we're creating a loop that continuously publishes a message to the &lt;code&gt;CPU/info&lt;/code&gt; topic. The message contains a json payload with &lt;code&gt;temperature&lt;/code&gt; value, which could be then extended further in a real-world application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Deploying the Message Publisher Component
&lt;/h2&gt;

&lt;p&gt;For deploying the new component to the device we should extend the &lt;code&gt;deployment.json.template:&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "targetArn": "arn:aws:iot:$AWS_REGION:$AWS_ACCOUNT_ID:thinggroup/$THING_GROUP",
    "deploymentName": "Main deployment",
    "components": {
        "com.example.hello": {
            "componentVersion": "LATEST",
            "runWith": {}
        },
        "com.example.world": {
            "componentVersion": "LATEST",
            "runWith": {}
        },
        "com.example.pub": {
            "componentVersion": "LATEST",
            "runWith": {}
        }
    },
    "deploymentPolicies": {
        "failureHandlingPolicy": "ROLLBACK",
        "componentUpdatePolicy": {
            "timeoutInSeconds": 60,
            "action": "NOTIFY_COMPONENTS"
        },
        "configurationValidationPolicy": {
            "timeoutInSeconds": 60
        }
    },
    "iotJobConfiguration": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've followed our previous blog post, you should have your GitHub Actions set up for your repository. This setup allows for automatic deployment of your components. &lt;/p&gt;

&lt;p&gt;When you create a new component and commit it to your repository, make sure to add it to the &lt;code&gt;deployment.json.template&lt;/code&gt;. This step is crucial as it ensures your component is included in the deployment process.&lt;/p&gt;

&lt;p&gt;After committing the new component, the GitHub Actions workflow will trigger, resulting in the automatic deployment of your component to the targeted device, in this case, a Raspberry Pi.&lt;/p&gt;

&lt;p&gt;Once deployed, the component will start running on the Raspberry Pi. It will begin publishing messages to the specified AWS IoT topic. &lt;/p&gt;

&lt;p&gt;To verify that your component is functioning correctly, you can subscribe to the topic in the AWS IoT Core console. Here, you'll be able to observe the incoming messages, confirming that your component is publishing as expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, we've walked through the process of developing a Greengrass Publish component on a Raspberry Pi. This is a great way to use the messaging system for your IoT applications, and I hope it helps you on your journey with AWS IoT Greengrass.&lt;/p&gt;

&lt;p&gt;For reference, please refer to &lt;a href="https://github.com/aws-iot-builder-tools/greengrass-continuous-deployments"&gt;this&lt;/a&gt; GitHub repo.&lt;br&gt;
Stay tuned for more posts on advanced Greengrass component development and other IoT topics. Happy coding!&lt;/p&gt;

&lt;p&gt;If you have any feedback about this post, or you would like to see more related content, please reach out to me here, or on &lt;a href="https://twitter.com/nenadilic84"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/nenadilic84/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>greengrass</category>
      <category>aws</category>
      <category>iot</category>
    </item>
    <item>
      <title>AWS IoT Greengrass Components Deployment with GDK using GitHub Actions</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Tue, 06 Jun 2023 11:01:34 +0000</pubDate>
      <link>https://dev.to/iotbuilders/aws-iot-greengrass-components-deployment-with-gdk-using-github-actions-245m</link>
      <guid>https://dev.to/iotbuilders/aws-iot-greengrass-components-deployment-with-gdk-using-github-actions-245m</guid>
      <description>&lt;p&gt;As IoT deployments grow, a set of distinct challenges arise when it comes application consistency across a broad spectrum of devices: efficiently managing update rollbacks, and maintaining comprehensive, auditable change logs can all present significant obstacles. However, these challenges can be effectively managed using AWS IoT Greengrass and the Greengrass Development Kit (GDK).&lt;/p&gt;

&lt;p&gt;AWS IoT Greengrass enables the deployment of applications directly to your IoT devices, simplifying the management and control of device-side software. The GDK further enhances this capability by streamlining the configuration and packaging of these applications for deployment, making it easier to get your applications onto your devices.&lt;/p&gt;

&lt;p&gt;To create a robust and efficient system, we can also introduce GitOps methodologies. GitOps leverages version control, automated deployments, and continuous monitoring to improve the reliability and efficiency of your deployment processes. By using these methodologies with GitHub Actions, we can automate the deployment process, triggering it with every commit or merge to a specified branch.&lt;/p&gt;

&lt;p&gt;In this blog post, we'll explore how these technologies and methodologies can be combined to create a powerful, scalable, and automated IoT deployment system. We'll walk through the setup of the GDK, the definition and deployment of Greengrass components, and the setup of a GitHub Actions workflow to automate the entire process. &lt;/p&gt;

&lt;p&gt;Let’s dive into and get started with this setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;The AWS IoT Greengrass Development Kit Command-Line Interface (GDK CLI) is an open-source tool designed to streamline the creation, building, and publishing of custom Greengrass components. It simplifies the version management process, allows starting projects from templates or community components, and can be customized to meet specific development needs.&lt;/p&gt;

&lt;p&gt;It can also be effectively utilized with GitHub Actions to automate the process of building and publishing Greengrass components. This could be a crucial part of a Continuous Integration/Continuous Deployment (CI/CD) pipeline. Here's a general outline of how this could be done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Install Dependencies&lt;/strong&gt;: Create a GitHub Actions workflow file (e.g., &lt;code&gt;.github/workflows/main.yml&lt;/code&gt;) and start with a job that sets up the necessary environment. This includes installing Python and pip (since GDK CLI is a Python tool), AWS CLI, and the GDK CLI itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure AWS Credentials&lt;/strong&gt;: Use GitHub Secrets to securely store your AWS credentials (Access Key ID and Secret Access Key). In your workflow, configure AWS CLI with these credentials so that the GDK CLI can interact with your AWS account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build and Publish Components&lt;/strong&gt;: Use GDK CLI commands in your workflow to build and publish your components. For example, you might have steps that run commands like &lt;code&gt;gdk component build&lt;/code&gt; and &lt;code&gt;gdk component publish&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integrate with Other Workflows&lt;/strong&gt;: If you have other workflows in your CI/CD pipeline (such as running tests or deploying to other environments), you can use the output of the GDK CLI commands as inputs to these workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this way, every time you push a change to your Greengrass component source code on GitHub, the GDK CLI can automatically build and publish the updated component, ensuring that your Greengrass deployments are always using the latest version of your components.&lt;/p&gt;

&lt;p&gt;Furthermore, we can initiate a Greengrass deployment based on the deployment template in the next stage of the pipeline, after a successful build and publish. This can target a specific Thing Group, enabling us to reflect changes across a fleet of devices. With this approach, if we have dev and test branches, each of these can be mapped to selected Thing Groups. This allows us to perform field validation on selected devices, providing an efficient way to test changes in a controlled environment before wider deployment.&lt;/p&gt;

&lt;p&gt;For further details on creating GitHub Actions workflows, refer to the &lt;a href="https://docs.github.com/en/actions"&gt;GitHub Actions documentation&lt;/a&gt;. For more information about using the GDK CLI, please refer to the &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-development-kit-cli.html"&gt;GDK CLI documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Project Setup
&lt;/h2&gt;

&lt;p&gt;Based on the high level overview we can structure our project as such:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project
├── .github
│   └── workflows
│       └── main.yml
├── cfn
│   └── github-oidc
│       ├── oidc-provider.yaml
│       └── oidc-role.yaml
└── components
    ├── com.example.hello
    │   ├── gdk-config.json
    │   ├── main.py
    │   └── recipe.yaml
    ├── com.example.world
    │   ├── gdk-config.json
    │   ├── main.py
    │   └── recipe.yaml
    └── deployment.json.template
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where we have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.github/workflows/main.yml&lt;/code&gt;: Which is the GitHub Actions workflow file where the CI/CD pipeline is defined. The GDK CLI and AWS CLI setup, component building, publishing, and deployment tasks are defined here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cfn/github-oidc&lt;/code&gt;: This directory contains AWS CloudFormation templates (&lt;code&gt;oidc-provider.yaml&lt;/code&gt; and &lt;code&gt;oidc-role.yaml&lt;/code&gt;) that are used to set up an OIDC provider and role on AWS for authenticating GitHub Actions with AWS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;components&lt;/code&gt;: This directory contains the Greengrass components (&lt;code&gt;com.example.hello&lt;/code&gt; and &lt;code&gt;com.example.world&lt;/code&gt;) that you are developing. Each component has its own directory with:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;gdk-config.json&lt;/code&gt;: This is the configuration file for the GDK CLI for the specific component.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main.py&lt;/code&gt;: This is the main Python script file for the component's functionality.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;recipe.yaml&lt;/code&gt;: This is the component recipe that describes the component and its dependencies, lifecycle scripts, etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;deployment.json.template&lt;/code&gt;: This is a deployment template file for Greengrass deployments. It is used to generate the actual deployment file (&lt;code&gt;deployment.json&lt;/code&gt;) that is used when initiating a Greengrass deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  GitHub Actions and GDK Deployment Role Setup
&lt;/h2&gt;

&lt;p&gt;The CloudFormation template will be used to create an IAM role (&lt;code&gt;oidc-gdk-deployment&lt;/code&gt;) that provides the necessary permissions for building and deploying Greengrass components using GDK CLI and GitHub Actions. The role has specific policies attached that allow actions such as describing and creating IoT jobs, interacting with an S3 bucket for Greengrass component artifacts, and creating Greengrass components and deployments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSTemplateFormatVersion: 2010-09-09
Description: 'GitHub OIDC:| Stack: oidc'

Parameters:
  FullRepoName:
    Type: String
    Default: example/gdk-example

Resources:
  Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: oidc-gdk-deployment
      Policies:
        - PolicyName: iot-thing-group
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - iot:DescribeThingGroup
                  - iot:CreateJob
                Resource:
                  - !Sub arn:aws:iot:${AWS::Region}:${AWS::AccountId}:thinggroup/*
        - PolicyName: iot-jobs
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - iot:DescribeJob
                  - iot:CreateJob
                  - iot:CancelJob
                Resource:
                  - !Sub arn:aws:iot:${AWS::Region}:${AWS::AccountId}:job/*
        - PolicyName: s3-greengrass-bucket
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:CreateBucket
                  - s3:GetBucketLocation
                  - s3:ListBucket
                Resource:
                  - !Sub arn:aws:s3:::greengrass-component-artifacts-${AWS::Region}-${AWS::AccountId}
        - PolicyName: s3-greengrass-components
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource:
                  - !Sub arn:aws:s3:::greengrass-component-artifacts-${AWS::Region}-${AWS::AccountId}/*
        - PolicyName: greengrass-components
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - greengrass:CreateComponentVersion
                  - greengrass:ListComponentVersions
                Resource:
                  - !Sub arn:aws:greengrass:${AWS::Region}:${AWS::AccountId}:components:*
        - PolicyName: greengrass-deployment
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - greengrass:CreateDeployment
                Resource:
                  - !Sub arn:aws:greengrass:${AWS::Region}:${AWS::AccountId}:deployments
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Action: sts:AssumeRoleWithWebIdentity
            Principal:
              Federated: !Sub arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com
            Condition:
              StringLike:
                token.actions.githubusercontent.com:sub: !Sub repo:${FullRepoName}:*

Outputs:
  OidcRoleAwsAccountId:
    Value: !Ref AWS::AccountId
  OidcRoleAwsRegion:
    Value: !Ref AWS::Region
  OidcRoleAwsRoleToAssume:
    Value: !GetAtt Role.Arn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;FullRepoName&lt;/code&gt; parameter is used to specify the repository that the GitHub Actions workflow will be running in. This is important for the &lt;code&gt;sts:AssumeRoleWithWebIdentity&lt;/code&gt; action in the &lt;code&gt;AssumeRolePolicyDocument&lt;/code&gt;, which allows GitHub Actions to assume this IAM role for the specified repository. &lt;/p&gt;

&lt;p&gt;To deploy this CloudFormation stack, you would use the AWS Management Console, AWS CLI, or an AWS SDK. You would need to specify the &lt;code&gt;FullRepoName&lt;/code&gt; parameter as an input when you create the stack. For example, with the AWS CLI, you would use the &lt;code&gt;aws cloudformation deply&lt;/code&gt; command and provide the template file and the &lt;code&gt;FullRepoName&lt;/code&gt; parameter as inputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation deploy \
    --template-file cfn/github-oidc/oidc-role.yaml \
    --stack-name ga-gdk-role \
    --capabilities CAPABILITY_NAMED_IAM \
    --parameter-overrides FullRepoName=&amp;lt;your org&amp;gt;/&amp;lt;your repo name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup lays the foundation for the GitHub Actions and GDK CLI to work together to automate the building and deployment of Greengrass components.&lt;/p&gt;

&lt;p&gt;In scenario that you would like to use OIDC Provider for GitHub actions (suggested) you would also need to  set it up in you AWS account. Please not that this is needed only once per account region:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation deploy \
    --template-file cfn/github-oidc/oidc-provider.yaml \
    --stack-name oidc-provider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can go and prepare our Greengrass components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Greengrass Components GDK Setup
&lt;/h2&gt;

&lt;p&gt;Here we focus here on the configuration and implementation of our Greengrass components. These components form the core of our IoT solution, providing the required functionality on our Greengrass core devices.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;gdk-config.json&lt;/code&gt; file is where we configure our Greengrass component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "component": {
      "com.example.hello": {
        "author": "Example",
        "version": "NEXT_PATCH",
        "build": {
          "build_system": "zip"
        },
        "publish": {
          "bucket": "greengrass-component-artifacts",
          "region": "eu-west-1"
        }
      }
    },
    "gdk_version": "1.2.0"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the provided example, we have a single component named "com.example.hello". This file specifies the author, the build system (which is set to "zip" here), and the AWS S3 bucket details where the component will be published. The version field is set to "NEXT_PATCH", which means GDK will automatically increment the patch version of the component every time it's built.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;recipe.yaml&lt;/code&gt; file is the recipe for our Greengrass component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
RecipeFormatVersion: "2020-01-25"
ComponentName: "{COMPONENT_NAME}"
ComponentVersion: "{COMPONENT_VERSION}"
ComponentDescription: "This is a simple Hello World component written in Python."
ComponentPublisher: "{COMPONENT_AUTHOR}"
ComponentConfiguration:
  DefaultConfiguration:
    Message: "Hello"
Manifests:
  - Platform:
      os: all
    Artifacts:
      - URI: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/com.example.hello.zip"
        Unarchive: ZIP
    Lifecycle:
      Run: "python3 -u {artifacts:decompressedPath}/com.example.hello/main.py {configuration:/Message}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It contains essential metadata about the component, like its name, version, description, and publisher. It also specifies the default configuration, which, in this case, sets the default message to "Hello". The Manifests section describes the component's artifacts and the lifecycle of the component. In this instance, it specifies the location of the component's zipped artifacts and the command to run the component.&lt;/p&gt;

&lt;p&gt;Finally, the &lt;code&gt;main.py&lt;/code&gt; file is the Python script that our Greengrass component runs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import sys

message = f"Hello, {sys.argv[1]}!"

# Print the message to stdout, which Greengrass saves in a log file.
print(message)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script simply prints out a greeting message. The message is constructed from the argument passed to the script, which comes from the component configuration in the &lt;code&gt;recipe.yaml&lt;/code&gt; file. This setup demonstrates how you can pass configuration to your Greengrass components, as we can see in the “com.example.world” example where we provide “World” as a configuration message.&lt;/p&gt;

&lt;p&gt;In addition to the component configuration and scripts, we also define a &lt;code&gt;deployment.json.template&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "targetArn": "arn:aws:iot:$AWS_REGION:$AWS_ACCOUNT_ID:thinggroup/$THING_GROUP",
    "deploymentName": "Main deployment",
    "components": {
        "com.example.hello": {
            "componentVersion": "LATEST",
            "runWith": {}
        },
        "com.example.world": {
            "componentVersion": "LATEST",
            "runWith": {}
        }
    },
    "deploymentPolicies": {
        "failureHandlingPolicy": "ROLLBACK",
        "componentUpdatePolicy": {
            "timeoutInSeconds": 60,
            "action": "NOTIFY_COMPONENTS"
        },
        "configurationValidationPolicy": {
            "timeoutInSeconds": 60
        }
    },
    "iotJobConfiguration": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file specifies the deployment configuration for our Greengrass components. The &lt;code&gt;targetArn&lt;/code&gt; is the Amazon Resource Name (ARN) of the Greengrass thing group where we aim to deploy our components. In this example, we're deploying two components, &lt;code&gt;com.example.hello&lt;/code&gt; and &lt;code&gt;com.example.world&lt;/code&gt;, both set to use their latest versions. The &lt;code&gt;deploymentPolicies&lt;/code&gt; section sets the policies for failure handling, component update, and configuration validation. This file is vital as it governs how the deployment of our Greengrass components is handled in the target IoT devices.&lt;/p&gt;

&lt;p&gt;Please note that this is a template and we will be using this in our pipeline to replace the ARN accordingly.&lt;/p&gt;

&lt;p&gt;Taken together, these files form the basis of a Greengrass component. By modifying these templates and scripts, you can create your own custom Greengrass components with GDK. The next step is to set up GitHub Actions to automate the build and deployment of these components.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions Setup
&lt;/h2&gt;

&lt;p&gt;This GitHub workflow file sets up two jobs, namely &lt;code&gt;publish&lt;/code&gt; and &lt;code&gt;deploy&lt;/code&gt;, which are run when either a push to the &lt;code&gt;main&lt;/code&gt; branch occurs or the workflow is manually dispatched.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Publish Job
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;publish&lt;/code&gt; job runs on the &lt;code&gt;ubuntu-latest&lt;/code&gt; environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  publish:
    name: Component publish
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read

    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0
        ref: ${{ github.head_ref }}
    - uses: actions/setup-python@v3
      with:
        python-version: '3.9'

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: ${{ secrets.OIDC_ROLE_AWS_ROLE_TO_ASSUME }}
        aws-region: ${{ secrets.OIDC_ROLE_AWS_REGION }}

    - name: Install Greengrass Development Kit
      run: pip install -U git+https://github.com/aws-greengrass/aws-greengrass-gdk-cli.git@v1.2.3

    - name: GDK Build and Publish
      id: build_publish
      run: |

        CHANGED_COMPONENTS=$(git diff --name-only HEAD~1 HEAD | grep "^components/" | cut -d '/' -f 2)

        echo "Components changed -&amp;gt; $CHANGED_COMPONENTS"        

        for component in $CHANGED_COMPONENTS
        do
          cd $component
          echo "Building $component ..."
          gdk component build
          echo "Publishing $component ..."
          gdk component publish
          cd ..
        done

      working-directory: ${{ env.working-directory }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start with checking out the code from the repository and setting up Python 3.9. The AWS credentials are then configured using the &lt;code&gt;aws-actions/configure-aws-credentials@v1&lt;/code&gt; action. The credentials used here are fetched from the GitHub secrets &lt;code&gt;OIDC_ROLE_AWS_ROLE_TO_ASSUME&lt;/code&gt; and &lt;code&gt;OIDC_ROLE_AWS_REGION&lt;/code&gt;. The &lt;code&gt;OIDC_ROLE_AWS_ROLE_TO_ASSUME&lt;/code&gt; secret should contain the ARN of the AWS role that the GitHub Actions should assume when executing the workflow. This is the role we created in the firs step we can obtain it by executing the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation describe-stacks --stack-name ga-gdk-role --query 'Stacks[0].Outputs[?OutputKey==`OidcRoleAwsRoleToAssume`].OutputValue' --output text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;OIDC_ROLE_AWS_REGION&lt;/code&gt; secret should contain the AWS region where your resources are located. After that these variables needs to be added under &lt;code&gt;github.com/&amp;lt;org&amp;gt;/&amp;lt;repo&amp;gt;/settings/secrets/actions&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Next, the Greengrass Development Kit (GDK) is installed using pip. The GDK CLI is used to build and publish any components that have changed between the current and previous commit. &lt;/p&gt;

&lt;p&gt;The changed components are identified by looking at the differences between the current and previous commit and extracting the component names. Here it is important that the name of the folder mathces the name of the component.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Deploy Job
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;deploy&lt;/code&gt; job runs after the &lt;code&gt;publish&lt;/code&gt; job has completed successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  deploy:
    name: Component deploy
    runs-on: ubuntu-latest
    needs: publish
    permissions:
      id-token: write
      contents: read

    steps:
    - name: Checkout
      uses: actions/checkout@v3
      with:
        fetch-depth: 0
        ref: ${{ github.head_ref }}

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        role-to-assume: ${{ secrets.OIDC_ROLE_AWS_ROLE_TO_ASSUME }}
        aws-region: ${{ secrets.OIDC_ROLE_AWS_REGION }}

    - name: Deploy Greengrass components
      run: |
        export AWS_ACCOUNT_ID=$(aws sts get-caller-identity |  jq -r '.Account')
        export AWS_REGION=${GREENGRASS_REGION}
        # Thing Group is the name of the branch
        export THING_GROUP=${GITHUB_REF#refs/heads/}

        CHANGED_COMPONENTS=$(git diff --name-only HEAD~1 HEAD | grep "^components/" | cut -d '/' -f 2)

        if [ -z "$CHANGED_COMPONENTS" ]; then
          echo "No need to update deployment"
        else
          envsubst &amp;lt; "deployment.json.template" &amp;gt; "deployment.json"

          for component in $CHANGED_COMPONENTS
          do
            version=$(aws greengrassv2 list-component-versions \
              --output text \
              --no-paginate \
              --arn arn:aws:greengrass:${AWS_REGION}:${AWS_ACCOUNT_ID}:components:${component} \
              --query 'componentVersions[0].componentVersion')

            jq '.components[$component].componentVersion = $version' --arg component $component --arg version $version deployment.json &amp;gt; "tmp" &amp;amp;&amp;amp; mv "tmp" deployment.json

          done

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

          echo "Deployment finished!"
        fi

      working-directory: ${{ env.working-directory }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It follows a similar structure to the &lt;code&gt;publish&lt;/code&gt; job, starting with checking out the code from the repository and configuring AWS credentials using the same secrets.&lt;/p&gt;

&lt;p&gt;In the deployment step, it first identifies any changed components in a similar way as in the &lt;code&gt;publish&lt;/code&gt; job. If no components have changed, it does not proceed with deployment. If there are changed components, it prepares a &lt;code&gt;deployment.json&lt;/code&gt; file from the template, replacing placeholders with the actual values. It then gets the version of the changed components from AWS Greengrass and updates the &lt;code&gt;deployment.json&lt;/code&gt; file with these versions.&lt;/p&gt;

&lt;p&gt;Finally, it creates a deployment using the &lt;code&gt;aws greengrassv2 create-deployment&lt;/code&gt; command, providing the &lt;code&gt;deployment.json&lt;/code&gt; file as input and setting the region to the one specified in the &lt;code&gt;AWS_REGION&lt;/code&gt; environment variable.&lt;br&gt;
Here it is important to note that Thing Group is taken from the name of the branch &lt;code&gt;THING_GROUP=${GITHUB_REF#refs/heads/}&lt;/code&gt; as that way we can have different branches related to different Thing Groups as discussed above. In case the thing group is not create you can use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iot create-thing-group --thing-group-name main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, when ever there is a new commit on the main branch a process will kick start and issue a deployment to the specified group of devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this blog post, we've taken a deep dive into AWS IoT Greengrass V2, focusing on the usage of the Greengrass Development Kit (GDK) and how it can be automated with GitHub Actions. We started by setting up the GDK, explored the various components and how they interact, then we moved on to setting up a GitHub Actions workflow to automate the entire process.&lt;/p&gt;

&lt;p&gt;By leveraging AWS IoT Greengrass, the GDK, and GitHub Actions, you can create a powerful, scalable, and automated IoT solution. Whether you're managing a small group of IoT devices or a large fleet, this approach offers a robust and efficient way to handle your IoT application deployments.&lt;/p&gt;

&lt;p&gt;That's all for this blog post. We hope you found it informative and that it helps you on your journey to creating and managing IoT solutions with AWS IoT Greengrass. Happy coding!&lt;/p&gt;

&lt;p&gt;All the above code and setup can be referenced here:&lt;br&gt;
&lt;a href="https://github.com/aws-iot-builder-tools/greengrass-continuous-deployments"&gt;https://github.com/aws-iot-builder-tools/greengrass-continuous-deployments&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have any feedback about this post, or you would like to see more related content, please reach out to me here, or on &lt;a href="https://twitter.com/nenadilic84"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/nenadilic84/"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>greengras</category>
      <category>aws</category>
      <category>iot</category>
    </item>
    <item>
      <title>Fleet Provisioning for Embedded Linux Devices with AWS IoT Greengrass</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Thu, 04 May 2023 16:48:17 +0000</pubDate>
      <link>https://dev.to/iotbuilders/fleet-provisioning-for-embedded-linux-devices-with-aws-iot-greengrass-4h8b</link>
      <guid>https://dev.to/iotbuilders/fleet-provisioning-for-embedded-linux-devices-with-aws-iot-greengrass-4h8b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Managing a large fleet of embedded devices can be complex and challenging, particularly when it comes to creating a single image that can be flashed onto multiple devices. These devices must be able to self-provision, utilizing unique information such as their serial number, upon initial boot. In this blog post, we will discuss how AWS IoT Greengrass - Fleet Provisioning can streamline this process for embedded Linux devices, making it more efficient and reliable.&lt;/p&gt;

&lt;p&gt;For embedded systems engineers experienced in Embedded Linux and Yocto, we will guide you through building a Raspberry Pi Yocto image with Greengrass with Fleet Provisioning Plugin. This ensures seamless device provisioning and management, as well as automatic registration and configuration. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9rzwpi641sz8z8rhkar0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9rzwpi641sz8z8rhkar0.png" alt="Fleet provisioning by claim"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note here that the pre-provisioning lambda is optional but encouraged in order to additional layer of security. We will not be covering it in this post. You can learn more about it &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/pre-provisioning-hook.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the stage set, let's dive into the prerequisites for setting up AWS IoT Greengrass and Fleet Provisioning for your embedded Linux devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before diving into the process of preparing the host and configuring the Yocto image build, it's essential to set up AWS IoT Core. This involves creating policies, obtaining claim certificates, and ensuring that the AWS CLI is installed and configured. General information on how to accomplish this can be found in the &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/fleet-provisioning-setup.html" rel="noopener noreferrer"&gt;AWS IoT Greengrass Developer Guide&lt;/a&gt;.&lt;br&gt;
In summary, we will need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A token exchange IAM role, which core devices use to authorize calls to AWS services and An AWS IoT role alias that points to the token exchange role.&lt;/li&gt;
&lt;li&gt;An AWS IoT fleet provisioning template. The template must specify information needed for creating thing and policy which will be attached to greengrass core device created. You can either use existing IoT policy name or define the policy on the template.&lt;/li&gt;
&lt;li&gt;An AWS IoT provisioning claim certificate and private key for the fleet provisioning template.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Devices can be manufactured with a provisioning claim certificate and private key embedded in them. When the device connects first time to AWS IoT, it uses the claim certificate to register the new device and exchange it to unique device certificate. Provisioning claim certificate needs to have AWS IoT policy attached which allows devices to register and use the fleet provisioning template.&lt;/p&gt;

&lt;p&gt;To make this process more efficient, we can utilize a CloudFormation template that automates most of these steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  ProvisioningTemplateName:
    Type: String
    Default: 'GreengrassFleetProvisioningTemplate' 
  GGTokenExchangeRoleName:
    Type: String
    Default: 'GGTokenExchangeRole'
  GGFleetProvisioningRoleName:
    Type: String
    Default: 'GGFleetProvisioningRole'
  GGDeviceDefaultPolicyName:
    Type: String
    Default: 'GGDeviceDefaultIoTPolicy'
  GGProvisioningClaimPolicyName:
    Type: String
    Default: 'GGProvisioningClaimPolicy'

Resources:

  GGTokenExchangeRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref GGTokenExchangeRoleName
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - credentials.iot.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: '/'
      Policies:
        - PolicyName: !Sub ${GGTokenExchangeRoleName}Access
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - 'iot:DescribeCertificate'
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                  - 'logs:DescribeLogStreams'
                  - 's3:GetBucketLocation'
                Resource: '*'

  GGTokenExchangeRoleAlias:
    Type: AWS::IoT::RoleAlias
    Properties:
      RoleArn: !GetAtt GGTokenExchangeRole.Arn
      RoleAlias: !Sub ${GGTokenExchangeRoleName}Alias

  GGFleetProvisioningRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref GGFleetProvisioningRoleName
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - iot.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: '/'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AWSIoTThingsRegistration'

  GGDeviceDefaultPolicy:
    Type: AWS::IoT::Policy
    Properties:
      PolicyName: !Ref GGDeviceDefaultPolicyName
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
            - 'iot:Connect'
            - 'iot:Publish'
            - 'iot:Subscribe'
            - 'iot:Receive'
            - 'iot:Connect'
            - 'greengrass:*'
          Resource: '*'
        - Effect: Allow
          Action:
            - 'iot:AssumeRoleWithCertificate'
          Resource: !GetAtt GGTokenExchangeRoleAlias.RoleAliasArn

  GGFleetProvisionTemplate:
    Type: AWS::IoT::ProvisioningTemplate
    Properties:
      TemplateName: !Ref ProvisioningTemplateName
      Description: 'Fleet Provisioning template for AWS IoT Greengrass.'
      Enabled: True
      ProvisioningRoleArn: !GetAtt GGFleetProvisioningRole.Arn
      TemplateBody: !Sub |+ 
        {
          "Parameters": {
            "ThingName": {
              "Type": "String"
            },
            "ThingGroupName": {
              "Type": "String"
            },
            "AWS::IoT::Certificate::Id": {
              "Type": "String"
            }
          },
          "Resources": {
            "GGThing": {
              "OverrideSettings": {
                "AttributePayload": "REPLACE",
                "ThingGroups": "REPLACE",
                "ThingTypeName": "REPLACE"
              },
              "Properties": {
                "AttributePayload": {},
                "ThingGroups": [
                  {
                    "Ref": "ThingGroupName"
                  }
                ],
                "ThingName": {
                  "Ref": "ThingName"
                }
              },
              "Type": "AWS::IoT::Thing"
            },
            "GGDefaultPolicy": {
              "Properties": {
                "PolicyName": "${GGDeviceDefaultPolicyName}"
              },
              "Type": "AWS::IoT::Policy"
            },
            "GGCertificate": {
              "Properties": {
                "CertificateId": {
                  "Ref": "AWS::IoT::Certificate::Id"
                },
                "Status": "Active"
              },
              "Type": "AWS::IoT::Certificate"
            }
          }
        }

  GGProvisioningClaimPolicy:
    Type: AWS::IoT::Policy
    Properties:
      PolicyName: !Ref GGProvisioningClaimPolicyName
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action:
            - 'iot:Connect'
          Resource: '*'
        - Effect: Allow
          Action:
            - 'iot:Publish'
            - 'iot:Receive'
          Resource: 
            - !Sub 'arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topic/$aws/certificates/create/*'
            - !Sub 'arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topic/$aws/provisioning-templates/${ProvisioningTemplateName}/provision/*'
        - Effect: Allow
          Action:
            - 'iot:Subscribe'
          Resource:
            - !Sub 'arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topicfilter/$aws/certificates/create/*'
            - !Sub 'arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topicfilter/$aws/provisioning-templates/${ProvisioningTemplateName}/provision/*'

Outputs:

  GGTokenExchangeRole:
    Description: Name of token exchange role.
    Value: !Ref GGTokenExchangeRole
  GGTokenExchangeRoleAlias:
    Description: Name of token exchange role alias.
    Value: !Ref GGTokenExchangeRoleAlias
  GGFleetProvisionTemplate:
    Description: Name of Fleet provisioning template.
    Value: !Ref GGFleetProvisionTemplate
  GGProvisioningClaimPolicy:
     Description: Name of claim certificate IoT policy.
     Value: !Ref GGProvisioningClaimPolicy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file and create CloudFormation stack from template.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation create-stack --stack-name GGFleetProvisoning --template-body file://gg-fp.yaml --capabilities CAPABILITY_NAMED_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait few minutes for resources being created. You can check status from CloudFormation console or with command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation describe-stacks --stack-name GGFleetProvisoning
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create claim certificate
&lt;/h3&gt;

&lt;p&gt;These we will be embedded in our RPi SD Card Image and used to provision our devices.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir claim-certs

export CERTIFICATE_ARN=$(aws iot create-keys-and-certificate \
    --certificate-pem-outfile "claim-certs/claim.cert.pem" \
    --public-key-outfile "claim-certs/claim.pubkey.pem" \
    --private-key-outfile "claim-certs/claim.pkey.pem" \
    --set-as-active \
    --query certificateArn)

curl -o "claim-certs/claim.root.pem" https://www.amazontrust.com/repository/AmazonRootCA1.pem

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Attach the AWS IoT policy to the provisioning claim certificate
&lt;/h3&gt;

&lt;p&gt;As we created IoT policy named &lt;code&gt;GGProvisioningClaimPolicy&lt;/code&gt; with CloudFormation we can just use the name to attach the policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iot attach-policy --policy-name GGProvisioningClaimPolicy --target ${CERTIFICATE_ARN//\"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a Thing Group
&lt;/h3&gt;

&lt;p&gt;Once our devices get provisioned they will become part of this Thing Group allowing us later to target Thing Group Fleet Deployments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws iot create-thing-group --thing-group-name EmbeddedLinuxFleet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As of now we should be good to go and build our RPI image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building RPi Image
&lt;/h2&gt;

&lt;p&gt;Building a Yocto image for Raspberry Pi requires several steps, including setting up the build environment, cloning the necessary repositories, configuring the build, and finally, building the image itself. Here's a step-by-step guide to help you through the process:&lt;/p&gt;

&lt;p&gt;Open a terminal window on your workstation which has all the prerequisits based on the &lt;a href="https://docs.yoctoproject.org/brief-yoctoprojectqs/index.html" rel="noopener noreferrer"&gt;Yocto Project Build Doc&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE For the sake of this tutorial, the variable &lt;code&gt;BASE&lt;/code&gt; refers to the build environment parent directory. Here, this will be set to &lt;code&gt;$HOME&lt;/code&gt;. If you are using another partition as the base directory, please set it accordingly.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export BASEDIR=$(pwd)
export DIST=poky-rpi4
export B=kirkstone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone the Poky base layer to include OpenEmbedded Core, Bitbake, and so forth to seed the Yocto build environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone -b $B git://git.yoctoproject.org/poky.git $BASEDIR/$DIST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone additional dependent repositories. Note that we are cloning only what is required for AWS IoT Greengrass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone -b $B git://git.openembedded.org/meta-openembedded \
    $BASEDIR/$DIST/meta-openembedded
git clone -b $B git://git.yoctoproject.org/meta-raspberrypi \
    $BASEDIR/$DIST/meta-raspberrypi
git clone -b $B git://git.yoctoproject.org/meta-virtualization \
    $BASEDIR/$DIST/meta-virtualization
git clone -b $B https://github.com/aws4embeddedlinux/meta-aws \
    $BASEDIR/$DIST/meta-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Source the Yocto environment script. This seeds the &lt;code&gt;build/conf&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd $BASEDIR/$DIST
. ./oe-init-build-env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add necessary layers to &lt;code&gt;bblayers.conf&lt;/code&gt; using &lt;code&gt;bitbake-layer add-layer&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bitbake-layers add-layer ../meta-openembedded/meta-oe
bitbake-layers add-layer ../meta-openembedded/meta-python
bitbake-layers add-layer ../meta-openembedded/meta-filesystems
bitbake-layers add-layer ../meta-openembedded/meta-networking
bitbake-layers add-layer ../meta-virtualization
bitbake-layers add-layer ../meta-raspberrypi
bitbake-layers add-layer ../meta-aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure the &lt;code&gt;local.conf:&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here it is important to note that apart from standard raspberry pi configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MACHINE ?= "raspberrypi4-64"

DISABLE_VC4GRAPHICS = "1"

# Parallelism Options
BB_NUMBER_THREADS ?= "${@oe.utils.cpu_count()}"
PARALLEL_MAKE ?= "-j ${@oe.utils.cpu_count()}"

# Additional image features
USER_CLASSES ?= "buildstats"

# By default disable interactive patch resolution (tasks will just fail instead):
PATCHRESOLVE = "noop"

# Disk Space Monitoring during the build
BB_DISKMON_DIRS = "\
    STOPTASKS,${TMPDIR},1G,100K \
    STOPTASKS,${DL_DIR},1G,100K \
    STOPTASKS,${SSTATE_DIR},1G,100K \
    HALT,${TMPDIR},100M,1K \
    HALT,${DL_DIR},100M,1K \
    HALT,${SSTATE_DIR},100M,1K"

CONF_VERSION = "2"

DISTRO_FEATURES += "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_init_manager = "systemd"
VIRTUAL-RUNTIME_initscripts = ""

IMAGE_FSTYPES = "rpi-sdimg"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We should focus on our Greengrass FleetProvisioning configuration part, which should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
IMAGE_INSTALL:append = " greengrass-bin "
GGV2_DATA_EP     = "xxx-ats.iot.&amp;lt;your aws region&amp;gt;.amazonaws.com"
GGV2_CRED_EP     = "xxx.iot.&amp;lt;your aws region&amp;gt;.amazonaws.com"
GGV2_REGION      = "&amp;lt;your aws region&amp;gt;"
GGV2_THING_NAME  = "ELThing"
GGV2_TES_RALIAS  = "GGTokenExchangeRoleAlias" # we got this from the cloudformation
GGV2_THING_GROUP = "EmbeddedLinuxFleet"

PACKAGECONFIG:pn-greengrass-bin = "fleetprovisioning"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here it is important to note that we are adding &lt;code&gt;greengrass-bin&lt;/code&gt; to our image and then providing additional configuration required by the &lt;code&gt;config.yaml&lt;/code&gt; as well as adding &lt;code&gt;PACKAGECONFIG:pn-greengrass-bin = "fleetprovisioning"&lt;/code&gt; in order to enable the functionality.&lt;/p&gt;

&lt;p&gt;In order to get the AWS region and the IoT endpoints we can do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "GGV2_REGION="$(aws configure get region)
echo "GGV2_DATA_EP="$(aws --output text iot describe-endpoint \
    --endpoint-type iot:Data-ATS \
    --query 'endpointAddress')
echo "GGV2_CRED_EP="$(aws --output text iot describe-endpoint \
    --endpoint-type iot:CredentialProvider \
    --query 'endpointAddress')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note that we will need a unique Thing Name to be generated for each device, so here the Thing Name is taken as a prefix and there is script inside of a &lt;code&gt;greengreass-bin&lt;/code&gt; recipe that appends the unique device id to the Thing Name using the MAC address.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh
file_path="$1"
default_iface=$(busybox route | grep default | awk '{print $8}')
mac_address=$(busybox ifconfig "$default_iface" | grep -o -E '([[:xdigit:]]{1,2}:){5}[[:xdigit:]]{1,2}' | tr ':' '_')
sed -i "s/&amp;lt;unique&amp;gt;/$mac_address/g" "$file_path"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;meta-aws
└── recipes-iot
    └── aws-iot-greengrass
        └──files
            └── replace_board_id.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to replace this file with any other way of obtaining the uniqueness such as serial number or similar &lt;/p&gt;

&lt;p&gt;Finally we should copy our claim credentials we generated at the beginning to be included in our build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp  "claim-certs/claim.cert.pem" \
    "claim-certs/claim.pkey.pem" \
    "claim-certs/claim.root.pem" \
    $BASEDIR/$DIST/meta-aws/recipes-iot/aws-iot-greengrass/files/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please adjust the paths based on the location of generated certs and the recipe.&lt;/p&gt;

&lt;p&gt;After all of this we should proceed with building our image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bitbake core-image-minimal
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⌛ Couple of hours later ⌛ the build should be complete, and we can find the resulting image in the following directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls tmp/deploy/images/raspberrypi4-64/*sdimg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To flash the image onto an SD card, use a tool like 'dd'&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo dd if=tmp/deploy/images/raspberrypi4-64/core-image-minimal-raspberrypi4-64.sdimg of=/dev/sdX bs=4M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where we need to make sure to replace "/dev/sdX" with the appropriate device identifier for the SD card.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Please double check the SD card identifier as a mistake here can wipe your workstation system&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Powering the Device for the First Time
&lt;/h2&gt;

&lt;p&gt;Once the SD card is reinserted into the Raspberry Pi with power and internet connected, the device should perform provisioning and appear in the list of Greengrass core devices.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws greengrassv2 list-core-devices

{
    "coreDevices": [
        {
            "coreDeviceThingName": "ELThing_11_22_33_44_55_60",
            "status": "HEALTHY",
            "lastStatusUpdateTimestamp": "2023-04-25T15:39:00.703000+00:00"
        },
       {
            "coreDeviceThingName": "ELThing_11_22_33_44_55_61",
            "status": "HEALTHY",
            "lastStatusUpdateTimestamp": "2023-03-31T03:11:17.911000+00:00"
        },
       {
            "coreDeviceThingName": "ELThing_11_22_33_44_55_62",
            "status": "HEALTHY",
            "lastStatusUpdateTimestamp": "2023-02-25T15:17:29.505000+00:00"
        },        
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Success! &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To sum it up, managing a large fleet of embedded Linux devices can be a complex and challenging task, especially when it comes to creating a single image that can be flashed onto multiple devices. However, AWS IoT Greengrass with Fleet Provisioning can streamline this process and make it more efficient and reliable. In this blog post, we have discussed the prerequisites for setting up AWS IoT Greengrass and Fleet Provisioning, including creating policies, obtaining claim certificates, and configuring the Yocto image build. We have also provided a step-by-step guide to building a Yocto image for Raspberry Pi with Greengrass Fleet Provisioning configuration. Using AWS IoT Greengrass - Fleet Provisioning, managing a large fleet of embedded devices can be made easier, more efficient, and secure.&lt;/p&gt;

&lt;p&gt;If you have any feedback about this post, or you would like to see more related content, please reach out to me here, or on &lt;a href="https://twitter.com/nenadilic84" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/nenadilic84/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feel free to checkout this video that goes over the mentioned setup: &lt;a href="https://youtu.be/Eeo7GLVr0jw" rel="noopener noreferrer"&gt;https://youtu.be/Eeo7GLVr0jw&lt;/a&gt;&lt;/p&gt;

</description>
      <category>greengrass</category>
      <category>iot</category>
      <category>yocto</category>
    </item>
    <item>
      <title>Orchestrating Application Workloads in Distributed Embedded Systems: Writing and Scaling a Pub Application - Part 2</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Thu, 30 Mar 2023 19:23:24 +0000</pubDate>
      <link>https://dev.to/iotbuilders/orchestrating-application-workloads-in-distributed-embedded-systems-writing-and-scaling-a-pub-application-part-2-4je8</link>
      <guid>https://dev.to/iotbuilders/orchestrating-application-workloads-in-distributed-embedded-systems-writing-and-scaling-a-pub-application-part-2-4je8</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This blog covers the second part of &lt;a href="https://dev.to/iotbuilders/orchestrating-application-workloads-in-distributed-embedded-systems-setting-up-a-nomad-cluster-with-aws-iot-greengrass-part-1-1bdi"&gt;Orchestrating Application Workloads in Distributed Embedded Systems&lt;/a&gt;. We will go over how to expose Greengrass IPC in a Nomad cluster and have containerized applications publishing metrics to AWS IoT Core using the Greengrass IPC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwgdkooi1zamyrmp3r7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiwgdkooi1zamyrmp3r7r.png" alt="Architecture Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;It is essential to follow the first part of the blog, which covers bootstrapping devices with AWS IoT Greengrass and HashiCorp Nomad. Once that is done, we can jump into the application part and the required configuration. As a reminder, the source code is located here: &lt;a href="https://github.com/aws-iot-builder-tools/greengrass-nomad-demo" rel="noopener noreferrer"&gt;https://github.com/aws-iot-builder-tools/greengrass-nomad-demo&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Greengrass IPC Proxy
&lt;/h2&gt;

&lt;p&gt;In order for applications to access Greengrass IPC, we need to create a proxy. We will use &lt;code&gt;socat&lt;/code&gt; to forward the &lt;code&gt;ipc.socket&lt;/code&gt; via the network (TCP) and then use &lt;code&gt;socat&lt;/code&gt; on the application side to create an &lt;code&gt;ipc.socket&lt;/code&gt; file. The example can be found under &lt;code&gt;ggv2-nomad-setup/ggv2-proxy/ipc/recipe.yaml&lt;/code&gt;. Here we deploy the Nomad job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;job "ggv2-server-ipc" {&lt;/span&gt;
    &lt;span class="s"&gt;datacenters = ["dc1"]&lt;/span&gt;
    &lt;span class="s"&gt;type = "system"&lt;/span&gt;
    &lt;span class="s"&gt;group "server-ipc-group" {&lt;/span&gt;

        &lt;span class="s"&gt;constraint {&lt;/span&gt;
            &lt;span class="s"&gt;attribute = "\${meta.greengrass_ipc}"&lt;/span&gt;
            &lt;span class="s"&gt;operator  = "="&lt;/span&gt;
            &lt;span class="s"&gt;value     = "server"&lt;/span&gt;
        &lt;span class="s"&gt;}&lt;/span&gt;

        &lt;span class="s"&gt;network {&lt;/span&gt;
            &lt;span class="s"&gt;port "ipc_socat" {&lt;/span&gt;
                &lt;span class="s"&gt;static = &lt;/span&gt;&lt;span class="m"&gt;3307&lt;/span&gt;
            &lt;span class="err"&gt;}&lt;/span&gt;
        &lt;span class="err"&gt;}&lt;/span&gt;
        &lt;span class="s"&gt;service {&lt;/span&gt;
            &lt;span class="s"&gt;name = "ggv2-server-ipc"&lt;/span&gt;
            &lt;span class="s"&gt;port = "ipc_socat"&lt;/span&gt;
            &lt;span class="s"&gt;provider = "nomad"&lt;/span&gt;
        &lt;span class="s"&gt;}&lt;/span&gt;

        &lt;span class="s"&gt;task "server-ipc-task" {&lt;/span&gt;
            &lt;span class="s"&gt;driver = "raw_exec"&lt;/span&gt;
            &lt;span class="s"&gt;config {&lt;/span&gt;
                &lt;span class="s"&gt;command = "socat"&lt;/span&gt;
                &lt;span class="s"&gt;args = [&lt;/span&gt;
                    &lt;span class="s"&gt;"TCP-LISTEN:3307,fork,nonblock",&lt;/span&gt;
                    &lt;span class="s"&gt;"UNIX-CONNECT:$AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT,nonblock"&lt;/span&gt;
                &lt;span class="s"&gt;]&lt;/span&gt;
            &lt;span class="s"&gt;}&lt;/span&gt;
        &lt;span class="s"&gt;}&lt;/span&gt;
    &lt;span class="s"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This job will use the &lt;code&gt;AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT&lt;/code&gt; provided by the Greengrass Component deployment and run a &lt;code&gt;socat&lt;/code&gt; command by connecting to the defined socket and exposing it over TCP on a reserved port 3307. Note that the deployment of this job will have constraints and will only target the devices tagged as &lt;code&gt;greengrass_ipc=server&lt;/code&gt;, as this is intended to be deployed only on a client where Greengrass is running.&lt;/p&gt;

&lt;p&gt;To deploy this to our Greengrass device, we will use the same methods from the previous blog post. Which should look something like this:&lt;/p&gt;

&lt;p&gt;Start with building and publishing the component by doing &lt;code&gt;gdk build&lt;/code&gt; and &lt;code&gt;gdk publish&lt;/code&gt;, making sure you are in the &lt;code&gt;ggv2-nomad-setup/ggv2-proxy/ipc/&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Additionally, to deploy this to the targets, we will need to add this to a &lt;code&gt;deployment.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        "ggv2.nomad.proxy.ipc": {
            "componentVersion": "1.0.0",
            "runWith": {}
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;respecting the name of the component and the version provided by the GDK.&lt;/p&gt;

&lt;p&gt;After that executing the command below will deploy it to our target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws greengrassv2 create-deployment \
    --cli-input-json file://deployment.json\
    --region ${AWS_REGION}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the command executes successfully, we will be ready to move forward with our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application Overview
&lt;/h2&gt;

&lt;p&gt;We will have a simple application written in python that publishes information about used memory and CPU and publishes this information using the Greengrass IPC to AWS IoT Core. The topic here is constructed by having &lt;code&gt;NOMAD_SHORT_ALLOC_ID&lt;/code&gt; as a prefix followed by &lt;code&gt;/iot/telemetry.&lt;/code&gt; We will use this info later once we scale the application across the cluster and start receiving messages on multiple MQTT topics.&lt;/p&gt;

&lt;p&gt;Here is the Python code for the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json
import time
import os

import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.model as model


NOMAD_SHORT_ALLOC_ID = os.getenv('NOMAD_SHORT_ALLOC_ID')

def get_used_mem():
    with open('/proc/meminfo', 'r') as f:
        for line in f:
            if line.startswith('MemTotal:'):
                total_mem = int(line.split()[1]) * 1024  # convert to bytes
            elif line.startswith('MemAvailable:'):
                available_mem = int(line.split()[1]) * 1024  # convert to bytes
                break

    return total_mem - available_mem

def get_cpu_usage():
    with open('/proc/stat', 'r') as f:
        line = f.readline()
        cpu_time = sum(map(int, line.split()[1:]))
        idle_time = int(line.split()[4])

    return (cpu_time - idle_time) / cpu_time

if __name__ == '__main__':
    ipc_client = awsiot.greengrasscoreipc.connect()

    while True:
        telemetry_data = {
            "timestamp": int(round(time.time() * 1000)),
            "used_memory": get_used_mem(),
            "cpu_usage": get_cpu_usage()
        }

        op = ipc_client.new_publish_to_iot_core()
        op.activate(model.PublishToIoTCoreRequest(
            topic_name=f"{NOMAD_SHORT_ALLOC_ID}/iot/telemetry",
            qos=model.QOS.AT_LEAST_ONCE,
            payload=json.dumps(telemetry_data).encode(),
        ))
        try:
            result = op.get_response().result(timeout=5.0)
            print("successfully published message:", result)
        except Exception as e:
            print("failed to publish message:", e)

        time.sleep(5)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application can be found under &lt;code&gt;examples/nomad/nomad-docker-pub/app.py.&lt;/code&gt; On top of this we will be using a &lt;code&gt;Dokerfile&lt;/code&gt; to containerized. In order for this to work with GDK, we will be using &lt;code&gt;build_system: "custom"&lt;/code&gt; and specify the script for building and publishing the image to ECR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "component": {
    "nomad.docker.pub": {
      "author": "Nenad Ilic",
      "version": "NEXT_PATCH",
      "build": {
        "build_system": "custom",
        "custom_build_command": [
          "./build.sh"
         ]
      },
      "publish": {
        "bucket": "greengrass-component-artifacts",
        "region": "eu-west-1"
      }
    }
  },
  "gdk_version": "1.1.0"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;build.sh&lt;/code&gt; will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
set -e
AWS_ACCOUNT_ID=$(aws sts get-caller-identity |  jq -r '.Account')
AWS_REGION=$(jq -r '.component | to_entries[0] | .value.publish.region' gdk-config.json)
COMPONENT_NAME=$(jq -r '.component | keys | .[0]' gdk-config.json)
COMPONENT_AUTHOR=$(jq -r '.component | to_entries[0] | .value.author' gdk-config.json)
COMPONENT_NAME_DIR=$(echo $COMPONENT_NAME | tr '.' '-')

rm -rf greengrass-build
mkdir -p greengrass-build/artifacts/$COMPONENT_NAME/NEXT_PATCH
mkdir -p greengrass-build/recipes
cp recipe.yaml greengrass-build/recipes/recipe.yaml
sed -i "s/{COMPONENT_NAME}/$COMPONENT_NAME/" greengrass-build/recipes/recipe.yaml
sed -i "s/{COMPONENT_AUTHOR}/$COMPONENT_AUTHOR/" greengrass-build/recipes/recipe.yaml
sed -i "s/{AWS_ACCOUNT_ID}/$AWS_ACCOUNT_ID/" greengrass-build/recipes/recipe.yaml
sed -i "s/{AWS_REGION}/$AWS_REGION/" greengrass-build/recipes/recipe.yaml
sed -i "s/{COMPONENT_NAME_DIR}/$COMPONENT_NAME_DIR/" greengrass-build/recipes/recipe.yaml

docker build -t $COMPONENT_NAME_DIR .
docker tag $COMPONENT_NAME_DIR:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$COMPONENT_NAME_DIR:latest

if aws ecr describe-repositories --region $AWS_REGION --repository-names $COMPONENT_NAME_DIR &amp;gt; /dev/null 2&amp;gt;&amp;amp;1
then
    echo "Repository $COMPONENT_NAME_DIR already exists."
else
    # Create the repository if it does not exist
    aws ecr create-repository --region $AWS_REGION --repository-name $COMPONENT_NAME_DIR
    echo "Repository $COMPONENT_NAME_DIR created."
fi
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$COMPONENT_NAME_DIR:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script assumes the AWS CLI is installed and gets all the necessary configuration from the &lt;code&gt;gdk-config.json&lt;/code&gt; . The build script will create the appropriate recipe, build the docker image, login to ECR and push it referencing the component name set in the &lt;code&gt;gdk-config.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally the Nomad Job for deploying the application will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;job "nomad-docker-pub-example" {
    datacenters = ["dc1"]
    type = "service"
    group "pub-example-group" {
        count = 1
        constraint {
            attribute = "\${meta.greengrass_ipc}"
            operator  = "="
            value     = "client"
        }
        task "pub-example-task" {
            driver = "docker"
            config {
                image = "{AWS_ACCOUNT_ID}.dkr.ecr.{AWS_REGION}.amazonaws.com/{COMPONENT_NAME_DIR}:latest"
                command = "/bin/bash"
                args = ["-c", "socat UNIX-LISTEN:\$AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT,fork,nonblock TCP-CONNECT:\$GGV2_SERVER_IPC_ADDRESS,nonblock &amp;amp; python3 -u /pyfiles/app.py "]
            }
            env {
                AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT = "/tmp/ipc.socket"
                SVCUID="$SVCUID"
            }
            template {
                data = &amp;lt;&amp;lt;EOF
# Get all services and add them to env variables with their names
{{ range nomadServices }}
    {{- range nomadService .Name }}
    {{ .Name | toUpper | replaceAll "-" "_" }}_ADDRESS={{ .Address}}:{{ .Port }}{{- end }}
{{ end -}}
EOF
                destination = "local/env"
                env = true
            }
        }
    }
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Constraint - 
We are starting with our constraint where this application should be deployed. In this scenario, it would be targeting only Nomad clients where &lt;code&gt;greengrass_ipc=client&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Task - 
Next, we have our task with the Docker driver. Here, we get the image from the ECR, where the variables &lt;code&gt;AWS_ACCOUNT_ID&lt;/code&gt;, &lt;code&gt;AWS_ACCOUNT_ID&lt;/code&gt;, and &lt;code&gt;COMPONENT_NAME_DIR&lt;/code&gt; will be replaced by the build script with the appropriate values. Finally, we come to our &lt;code&gt;command&lt;/code&gt; and &lt;code&gt;args&lt;/code&gt;. These values would override what is already defined by the &lt;code&gt;Dockerfile&lt;/code&gt;. In this scenario, we first create the &lt;code&gt;ipc.socket&lt;/code&gt; required by the application using &lt;code&gt;socat&lt;/code&gt;. The &lt;code&gt;SVCUID&lt;/code&gt; will be then provided by the Greengrass component at the time of running the job, thus provided as an environment variable inside the Docker container. &lt;/li&gt;
&lt;li&gt;Template - 
After that, we have a template section that we require to obtain the IP address of our &lt;code&gt;ggv2-server-ipc&lt;/code&gt; service that we created earlier. We do this by listing all the services and getting the IP addresses and exporting them as environment variables by also converting their names to uppercase letters and appending &lt;code&gt;_ADDRESS&lt;/code&gt; at the end. This provides our env variable &lt;code&gt;GGV2_SERVER_IPC_ADDRESS&lt;/code&gt; for our &lt;code&gt;socat&lt;/code&gt; command that then looks like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socat UNIX-LISTEN:$AWS_GG_NUCLEUS_DOMAIN_SOCKET_FILEPATH_FOR_COMPONENT,fork,nonblock TCP-CONNECT:$GGV2_SERVER_IPC_ADDRESS,nonblock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which provides the &lt;code&gt;ipc.socket&lt;/code&gt; before running the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -u /pyfiles/app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we have this set, we can then go build and publish the component by doing &lt;code&gt;gdk build&lt;/code&gt; and &lt;code&gt;gdk publish&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Additionally in order to deploy this to the targets we will need to add this to a &lt;code&gt;deployment.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        "nomad.docker.pub": {
            "componentVersion": "1.0.0",
            "runWith": {}
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;respecting the name of the component and the version provided by the GDK.&lt;br&gt;
After that executing the command below will deploy it to our target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws greengrassv2 create-deployment \
    --cli-input-json file://deployment.json\
    --region ${AWS_REGION}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will be ready to scale our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling the Application
&lt;/h2&gt;

&lt;p&gt;As of now we should have our application running and publishing the data from a single client, however if we require to spread this application across the cluster, in this scenario second client, and have it report the memory and CPU usage, we can do this by simply changing the &lt;code&gt;count=1&lt;/code&gt; to &lt;code&gt;count=2&lt;/code&gt; in our job file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--- a/examples/nomad/nomad-docker-pub/recipe.yaml
+++ b/examples/nomad/nomad-docker-pub/recipe.yaml
@@ -31,7 +31,7 @@ Manifests:
             type = "service"

             group "pub-example-group" {
-              count = 1
+              count = 2
               constraint {
                 attribute = "\${meta.greengrass_ipc}"
                 operator  = "="
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use the same method to redeploy.&lt;/p&gt;

&lt;p&gt;Now if we go to AWS console and under AWS IoT → MQTT test client we can subscribe to topics &lt;code&gt;&amp;lt;NOMAD_SHORT_ALLOC_ID&amp;gt;/iot/telemetry&lt;/code&gt; and should be able to see messages coming. In order to get this ID we can simply run the following command on our device where the nomad server is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nomad status nomad-docker-pub-example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we will find the ID int the Allocations section that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Allocations
ID        Node ID   Task Group         Version  Desired  Status  Created     Modified
5dce9e1a  6ad1a15c  pub-example-group  10       run      running 1m28s ago   32s ago
8c517389  53c96910  pub-example-group  10       run      running 1m28s ago   49s ago
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will then allow us to construct those MQTT topics and start seeing the messages coming from those two instances of our application:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zyv44xltvakvcpbxe1o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1zyv44xltvakvcpbxe1o.png" alt="MQTT Client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next part we will take a look on how to access AWS services from the device using Token Exchange Service (TES).&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In this blog post, we covered how to expose the Greengrass IPC in a Nomad cluster, allowing a containerized application to publish metrics to AWS IoT Core using Greengrass IPC. We demonstrated how to create a proxy using &lt;code&gt;socat&lt;/code&gt; to forward the &lt;code&gt;ipc.socket&lt;/code&gt; via network (TCP) and how to set up an application that reports memory and CPU usage. We also showed how to scale the application across multiple clients in the cluster.&lt;/p&gt;

&lt;p&gt;By using AWS IoT Greengrass and HashiCorp Nomad, you can effectively manage, scale and monitor distributed embedded systems, making it easier to deploy and maintain complex IoT applications.&lt;/p&gt;

&lt;p&gt;If you have any feedback about this post, or you would like to see more related content, please reach out to me here, or on &lt;a href="https://twitter.com/nenadilic84" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/nenadilic84/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Orchestrating Application Workloads in Distributed Embedded Systems: Setting up a Nomad Cluster with AWS IoT Greengrass - Part 1</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Thu, 02 Mar 2023 12:51:18 +0000</pubDate>
      <link>https://dev.to/iotbuilders/orchestrating-application-workloads-in-distributed-embedded-systems-setting-up-a-nomad-cluster-with-aws-iot-greengrass-part-1-1bdi</link>
      <guid>https://dev.to/iotbuilders/orchestrating-application-workloads-in-distributed-embedded-systems-setting-up-a-nomad-cluster-with-aws-iot-greengrass-part-1-1bdi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As interconnected, purpose-built Systems on Chips (SoCs) have become more popular in industrial and automotive settings, managing their software components, including application deployments, data processing, and network communication, has become more challenging. This is particularly important in factories and cars, where downtime and maintenance costs can have a significant impact on productivity. To address these issues, developers can use available orchestration tools to ensure that the system operates efficiently and effectively, and interface those distributed embedded systems from the cloud in order to enable changes and updates throughout their lifecycle.&lt;/p&gt;

&lt;p&gt;In this blog post series, we will demonstrate how to use &lt;a href="https://aws.amazon.com/greengrass/" rel="noopener noreferrer"&gt;AWS IoT Greengrass&lt;/a&gt; and &lt;a href="https://developer.hashicorp.com/nomad/docs" rel="noopener noreferrer"&gt;Hashicorp Nomad&lt;/a&gt; to seamlessly interface with multiple interconnected devices and orchestrate service deployments on them. Greengrass will allow us to view the cluster as a single "Thing" from the cloud perspective, while Nomad will serve as the primary cluster orchestration tool.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56qe1pp23gy3hk2ghbsi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F56qe1pp23gy3hk2ghbsi.png" alt="Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Part 1 of this series, we will cover how to set up a cluster of 3 devices with AWS IoT Greengrass already installed on one device, and then set up a cluster of 1 Nomad server/client and 2 Nomad clients.&lt;/p&gt;

&lt;p&gt;It's important to note that Nomad is a lightweight orchestration tool for distributed environments that comes as a single binary installation. This makes it easy to operate while still providing features that allow applications to run in high availability. In addition to running Docker containers, Nomad enables the execution of tasks on the cluster in other forms such as Java, exec, QEMU, and more.&lt;/p&gt;

&lt;p&gt;That being said, this tutorial is targeted for IoT engineers, embedded systems developers, and IoT DevOps engineers with a technical background in building and running applications on embedded systems, as well as basic knowledge about Greengrass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this specific example, we will be using 3 Raspberry Pis, but this setup should generally work on devices running Linux, thus having a 3 EC2’s running Ubuntu would be a good replacement. To get started, we will pick one of those 3 devices to be our server which will need to have AWS IoT Greengrass installed, by following these &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/getting-started.html" rel="noopener noreferrer"&gt;steps&lt;/a&gt; and by taking note of you Things Name and/or Thing Group. In this example we have used &lt;code&gt;nomad-cluster&lt;/code&gt; as a Thing Group. Additionally in order to follow along, please have a &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/gdk-cli-configuration-file.html" rel="noopener noreferrer"&gt;GDK&lt;/a&gt; installed on development host.&lt;/p&gt;

&lt;p&gt;Next, on two other devices, in order to be able to &lt;code&gt;ssh&lt;/code&gt; into them from the server and set up the Nomad clients, we will need to add the server’s public key to them. This can be done by using &lt;code&gt;ssh-keygen&lt;/code&gt; to generate the pair and then using &lt;code&gt;ssh-copy-id user@remote_host&lt;/code&gt; to copy the public key to other two devices. This will allow easier client setup using Greengrass components provided in the example repository. &lt;/p&gt;

&lt;p&gt;Please also note that we will be using root in this setup in order to allow certain application access, but this is not advised in production (we will discuss this in one of the following blogs). Also, instead of using IP addresses, it is advised for each device to have a unique hostname and responding DNS entry for easier use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bootstrapping the Nomad Cluster
&lt;/h2&gt;

&lt;p&gt;Now that we have all that in place we can start with bootstrapping the Nomad cluster. For this we will be using the following GitHub repository as a starting point by cloning it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/aws-iot-builder-tools/greengrass-nomad-demo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Nomad Server
&lt;/h3&gt;

&lt;p&gt;Next navigate to &lt;code&gt;ggv2-nomad-setup/cluster-bootstrap/nomad-server&lt;/code&gt; directory in the cloned repository. Here we can find a &lt;code&gt;recipe.yaml&lt;/code&gt; for our &lt;code&gt;nomad.bootstrap.server&lt;/code&gt; component as well as our &lt;code&gt;gdk-config.json&lt;/code&gt; which we can modify to reflect the current setup (region, author, bucket and so on...).&lt;/p&gt;

&lt;p&gt;Now we would be ready to build and publish our component by executing &lt;code&gt;gdk build&lt;/code&gt; and &lt;code&gt;gdk publish&lt;/code&gt; which will create the component, publish the artifact to an S3 bucket and version it.&lt;/p&gt;

&lt;p&gt;The component will include a &lt;code&gt;server.hcl&lt;/code&gt; file for setting up the nomad server/client that looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Increase log verbosity
log_level = "DEBUG"

# Setup data dir
data_dir = "/opt/nomad/data"

# Enable the server
server {
  enabled = true
}
# Enable the client as well
client {
  enabled = true
  meta {
    greengrass_ipc = "server"
  }
  options = {
    "driver.raw_exec.enable" = "1"
  }
}

# port for the ui
ports {
  http = 8080
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the Nomad client, we will add additional metadata &lt;code&gt;greengrass_ipc = "server"&lt;/code&gt; which will allow us to deploy services on a host where Greengrass is running and also enable &lt;code&gt;raw_exec&lt;/code&gt; driver by setting &lt;code&gt;"driver.raw_exec.enable" = "1"&lt;/code&gt; , and finally we will expose the Nomads UI on the 8080 port allowing us to view it in our local network for debugging purposes, of course this should be disabled in production environment.&lt;/p&gt;

&lt;p&gt;In the root of the repository we have &lt;code&gt;deployment.json.template&lt;/code&gt; which we can use to create a Greengrass deployment targeting our Thing Group, which in this scenario we called &lt;code&gt;nomad-cluster&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To reflect your set-up, you can adapt the template file to your needs and then run the commands below to populate the required variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS_ACCOUNT_ID=$(aws sts get-caller-identity |  jq -r '.Account')
AWS_REGION=eu-west-1
envsubst &amp;lt; "deployment.json.template" &amp;gt; "deployment.json"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we should be able to modify the &lt;code&gt;deployment.json&lt;/code&gt; file to only include the &lt;code&gt;nomad.bootstrap.server&lt;/code&gt; and the appropriate component version, which should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "targetArn": "arn:aws:iot:&amp;lt;AWS Region&amp;gt;:&amp;lt;AWS Account&amp;gt;:thinggroup/nomad-cluster",
    "deploymentName": "Deployment for nomad-cluster group",
    "components": {
        "nomad.bootstrap.server": {
            "componentVersion": "1.0.0",
            "runWith": {}
        }
    },
    "deploymentPolicies": {
        "failureHandlingPolicy": "ROLLBACK",
        "componentUpdatePolicy": {
            "timeoutInSeconds": 60,
            "action": "NOTIFY_COMPONENTS"
        },
        "configurationValidationPolicy": {
            "timeoutInSeconds": 60
        }
    },
    "iotJobConfiguration": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally deploy it to our target by executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws greengrassv2 create-deployment \
    --cli-input-json file://deployment.json\
    --region ${AWS_REGION}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This bootstraps the Nomad server on a device with Greengrass installed, and configures the Nomad client to enable the deployment of proxies for Greengrass IPC and Token Exchange Service. We will provide a detailed guide for setting up the client in the next blog post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nomad Clients
&lt;/h3&gt;

&lt;p&gt;For Nomad clients the process would be similar, with a difference of configuring and adding the DNS Names (or IPs) with usernames for each client, as well as server’s DNS (or IP) in the &lt;code&gt;recipe.yaml&lt;/code&gt; under &lt;code&gt;ggv2-nomad-setup/cluster-bootstrap/nomad-clients/recipe.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ComponentConfiguration:
  DefaultConfiguration:
    Server:
      DnsName: "rpi-server.local"
    Client:
      "1":
        UserName: root
        DnsName: "rpi-client1.local"
      "2":
        UserName: root
        DnsName: "rpi-client2.local"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is to allow the Greengrass component to install the Nomad clients using &lt;code&gt;ssh&lt;/code&gt; and adding configuring them so they can connect with the server.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;client.hcl&lt;/code&gt; which will be added to each Nomad client will look like this where the &lt;code&gt;&amp;lt;SERVER_DNS_NAME&amp;gt;&lt;/code&gt;will be replaced from the configuration provided in the recipe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Increase log verbosity
log_level = "DEBUG"

# Setup data dir
data_dir = "/opt/nomad/data"

client {
  enabled = true
  servers = ["&amp;lt;SERVER_DNS_NAME&amp;gt;"]
  meta {
    greengrass_ipc = "client"
  }
  options = {
    "driver.raw_exec.enable" = "1"
  }
}

# different port than server
ports {
  http = 5656
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that is done, we can proceed with building and publishing the component by doing &lt;code&gt;gdk build&lt;/code&gt; and &lt;code&gt;gdk publish&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;Additionally in order to deploy this to the targets we will need to add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        "nomad.bootstrap.clients": {
            "componentVersion": "1.0.0",
            "runWith": {}
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And execute the same command to deploy it to our target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws greengrassv2 create-deployment \
    --cli-input-json file://deployment.json\
    --region ${AWS_REGION}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the clients bootstrapped, we are ready to move on to the next steps in deploying a demo component to Greengrass and Nomad, and how to publish data to AWS IoT Core using Greengrass IPC, which we will do in the second part of this blog. &lt;/p&gt;

&lt;p&gt;It's worth noting that this is a demo deployment and not suitable for production environments. In a future blog post in this series, we will discuss how to set up Nomad for production environments, including security considerations and best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In Part 1 of this series, we have covered the importance of orchestrating application workloads in distributed embedded systems and how to set up a Nomad cluster with AWS IoT Greengrass. By following these steps, developers can ensure that their systems operate efficiently, reliably, and with optimal performance, while also allowing them to develop and deploy new services even after the systems are operational.&lt;/p&gt;

&lt;p&gt;In the next blog post, we will cover the next steps in the process of setting up a demo component to Greengrass and Nomad, and how to publish data to AWS IoT Core using Greengrass IPC. Stay tuned for Part 2 of this series!&lt;/p&gt;

&lt;p&gt;If you have any feedback about this post, or you would like to see more related content, please reach out to me here, or on &lt;a href="https://twitter.com/nenadilic84" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/nenadilic84/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>greengrass</category>
      <category>nomad</category>
    </item>
    <item>
      <title>Getting started with AWS IoT Greengrass and C# .NET development</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Thu, 19 Jan 2023 15:32:39 +0000</pubDate>
      <link>https://dev.to/iotbuilders/getting-started-with-aws-iot-greengrass-and-c-net-development-46im</link>
      <guid>https://dev.to/iotbuilders/getting-started-with-aws-iot-greengrass-and-c-net-development-46im</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this example, we'll be using a development machine with the following software installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;.NET Core SDK 6.0+&lt;/li&gt;
&lt;li&gt;Visual Studio Code with the C# extension installed&lt;/li&gt;
&lt;li&gt;An AWS account and AWS IoT Greengrass provisioned on a compatible device. For more info take a look at the &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/getting-started.html" rel="noopener noreferrer"&gt;Getting Started&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-development-kit-cli.html" rel="noopener noreferrer"&gt;Greengrass Development Kit CLI&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up the Development Environment
&lt;/h2&gt;

&lt;p&gt;The example is a located under &lt;a href="https://github.com/aws-iot-builder-tools/greeneyes/tree/main/blog-posts/002" rel="noopener noreferrer"&gt;greeneyes&lt;/a&gt; repository, which will utilise some of the scripts introduced in order to make easier development. For more details take a look at the initial &lt;a href="https://aws.amazon.com/blogs/iot/build-an-efficient-development-environment-for-aws-iot-greengrass/" rel="noopener noreferrer"&gt;blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That being said, let’s checkout the repository with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git@github.com:aws-iot-builder-tools/greeneyes.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Developing the Greengrass Component
&lt;/h2&gt;

&lt;p&gt;Now we're ready to start looking at our Greengrass component. Let's open the project in Visual Studio Code using the following command :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;Program.cs&lt;/code&gt; file, we can see our &lt;code&gt;Main&lt;/code&gt; 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 &lt;code&gt;greengrass/[AWS_IOT_THING_NAME]&lt;/code&gt; where &lt;code&gt;AWS_IOT_THING_NAME&lt;/code&gt; will be retrieved from a an environment set by the Greeengrass Nucleus.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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 =&amp;gt; Environment.GetEnvironmentVariable("AWS_IOT_THING_NAME");
        public static string ThingTopic =&amp;gt; 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 += (_, _) =&amp;gt; Running = false;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the Greengrass Component
&lt;/h2&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dotnet publish -c Release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above commands will create a directory structure for the Greengrass component artifact, zip the build and move it.&lt;/p&gt;

&lt;p&gt;Before we generate an appropriate component recipe we first need to make sure we have a correct &lt;code&gt;gdk-config.json&lt;/code&gt; as we will be using &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-development-kit-cli.html" rel="noopener noreferrer"&gt;Greengrass Development Kit CLI&lt;/a&gt; for the deployment.&lt;/p&gt;

&lt;p&gt;Here we have a &lt;code&gt;gdk-config.json.template&lt;/code&gt; file where we need to modify: author, bucket and region and save it as a &lt;code&gt;gdk-config.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "component": {
    "greeneyes.GGCSharp": {
      "author": "&amp;lt;PLACEHOLDER_AUTHOR&amp;gt;",
      "version": "NEXT_PATCH",
      "build": {
        "build_system": "custom",
        "custom_build_command": [ "./build.sh" ]
      },
      "publish": {
        "bucket": "&amp;lt;PLACEHOLDER_BUCKET&amp;gt;",
        "region": "&amp;lt;PLACEHOLDER_REGION&amp;gt;"
      }
    }
  },
  "gdk_version": "1.0.0"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For author we can simply put &lt;em&gt;BlogReader&lt;/em&gt;, but for s3 bucket and region we can use AWS CLI to populate those.&lt;br&gt;
For example for region we can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws configure get region
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $(sed 's/-//g' &amp;lt;&amp;lt;&amp;lt; $(hostname))$(head -c 8 /etc/machine-id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we can move to the component recipe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
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 &amp;amp;&amp;amp; {artifacts:decompressedPath}/GGCSharp/GGCSharp"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where we need to make sure we update the &lt;code&gt;{COMPONENT_NAME}&lt;/code&gt; and &lt;code&gt;{COMPONENT_AUTHOR}&lt;/code&gt; respectively, after moving the recipe to the &lt;code&gt;greengrass-build&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p greengrass-build/recipes
cp recipe.yaml greengrass-build/recipes/recipe.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once finished we can then simply use the gdk tool to build and publish the our Greengrass component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gdk component build
gdk component publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to make this easer a &lt;code&gt;build.sh&lt;/code&gt; script with the same instructions is located in the root folder of the example.&lt;/p&gt;

&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws greengrassv2 create-deployment \
          --cli-input-json file://deployment.json \
          --region ${AWS_REGION}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where the deployment.json could look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "targetArn": "arn:aws:iot:$AWS_REGION:$AWS_ACCOUNT_ID:thinggroup/&amp;lt;Thing Group&amp;gt;",
    "deploymentName": "Deployment for our group",
    "components": {
        "&amp;lt;COMPONENT_NAME&amp;gt;": {
            "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": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively we can use our project helper tools to deploy the component by simply executing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gg-cloud-deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which should do all the steps above. &lt;/p&gt;

&lt;h3&gt;
  
  
  Viewing Publishing Data
&lt;/h3&gt;

&lt;p&gt;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 &lt;code&gt;greengrass/[AWS_IOT_THING_NAME]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffphoqi3jujdxazka6oyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffphoqi3jujdxazka6oyp.png" alt="MQTT Test" width="771" height="909"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Currently, the only available method for IPC is &lt;code&gt;PublishToIotCore&lt;/code&gt;. However, other methods can be implemented by referencing the APIs provided in the python SDK, located a &lt;a href="https://github.com/aws/aws-iot-device-sdk-python-v2/blob/main/awsiot/greengrasscoreipc/model.py#L6337" rel="noopener noreferrer"&gt;here&lt;/a&gt;. In the future, we aim to integrate these methods directly into our &lt;code&gt;RpcMessages.cs&lt;/code&gt; for greater convenience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;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 &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/interact-with-aws-services.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Please reach out if you have any questions or need help with your development, we're always happy to help.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cybersecurity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Home Treadmill with AWS IoT Greengrass and RPi 0 W</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Thu, 24 Nov 2022 19:16:11 +0000</pubDate>
      <link>https://dev.to/iotbuilders/home-treadmill-with-aws-iot-greengrass-and-rpi-0-w-56j3</link>
      <guid>https://dev.to/iotbuilders/home-treadmill-with-aws-iot-greengrass-and-rpi-0-w-56j3</guid>
      <description>&lt;p&gt;This setup was inspired by a blog post &lt;a href="https://devopstar.com/2022/09/22/github-actions-for-aws-iot-greengrass-v2-continuous-deployment" rel="noopener noreferrer"&gt;Using GitHub Actions for Greengrass v2 Continuous Deployment&lt;/a&gt; after a talk at &lt;a href="https://twitter.com/i/spaces/1ynJOanQdpEKR" rel="noopener noreferrer"&gt;IoT Builders Session&lt;/a&gt;. After the discussion, I wanted to try out the Greengrass Continues Deployment setup using the Github Actions and realized I had the treadmill, which I might be able to retrofit for this purpose.&lt;/p&gt;

&lt;p&gt;In the setup, I'll use the same principles for deploying a Greengrass component with GitHub Actions and OIDC, which will allow me to develop and test a Greengrass component that publishes treadmill speed measurements to AWS IoT Core and saves them in Amazon Timestream using IoT Rules. After that, I'll configure an Amazon Managed Grafana to visualize and analyze how far I've run as well as my current, maximum, and average speed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfbdl3sod7ijened0xwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfbdl3sod7ijened0xwe.png" alt="Grafana Dashboard" width="800" height="470"&gt;&lt;/a&gt;&lt;br&gt;
As of now I’m at 20.5 km/h max speed 🐌&lt;/p&gt;
&lt;h2&gt;
  
  
  The Hardware Setup
&lt;/h2&gt;

&lt;p&gt;Personally, I’ve been trying to increase my sprinting speed and have been training on a curved treadmill, which doesn’t have any motors or require a power supply. One of the reasons I like running on this type of self-powered treadmill is that it allows me to run naturally on the balls of my feet. This motion creates momentum to turn the treadmill belt by pushing your body forward. The point of contact is significantly ahead of the center of mass; thus, the experience of support is different than with other non-motorized treadmill options and more similar to that of running on the ground.&lt;br&gt;
So after the previously mentioned talk with Nathan, I thought it would be nice to have a dashboard that tells me how much I’ve run and provides me with my current and maximal speed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx90ro0bgo1sfei310l2e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx90ro0bgo1sfei310l2e.png" alt="treadmill" width="800" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve noticed that there is a magnetic reed-switch that is triggered on each revolution of the conveyor drum, thus making the speed measurement setup easy to wire, so I decided to give it a try and setup my Greengrass CI/CD based on the mentioned blog and Github. Additionally, I had a spare Raspberry Pi Zero W with a battery module laying around, and I wanted to try using it with Greengrass.&lt;/p&gt;

&lt;p&gt;However, I needed to figure out how to determine the running speed based on the number of revolutions per second. In order to do this, I had to use the original speed meter display that came with my treadmill and simulate reed switch impulses by providing a 1Hz signal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ka27sxot13fjld2e7r9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ka27sxot13fjld2e7r9.png" alt="1Hz Signal" width="800" height="331"&gt;&lt;/a&gt;&lt;br&gt;
This gave me a running (walking) speed of 2.2 km/h. I then went on to test other frequencies ranging from 2 Hz to 17 Hz.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc43qlkqpywj2ev6ti20j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc43qlkqpywj2ev6ti20j.png" alt="2Hz Signal" width="800" height="328"&gt;&lt;/a&gt;&lt;br&gt;
The conclusion was that, as expected, there was a linear distribution between number of revolutions and treadmill speed, and the factor of conversion is 2.2, which made the code in RPi quite easy to write. Before jumping into the code, I had to wire the reed switch and connect it properly to the Raspberry using the wiring diagram below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntqvaujrq2tbqrcfdz8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntqvaujrq2tbqrcfdz8m.png" alt="Reed Switch Closed" width="800" height="1279"&gt;&lt;/a&gt;&lt;br&gt;
In this setup, every time a magnet crosses near the reed switch, I get a falling edge signal from 3.3V to 0V; thus, the time between falling edges gives one revolution of the conveyor drum.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpa5tto5vaxbczde35ud6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpa5tto5vaxbczde35ud6.png" alt="Reed Switch Opened" width="800" height="1276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the magnet rotates further, the voltage rises back to 3.3V, and we have a rising edge that will stay there for the next cycle until the magnet's magnetic field interacts with the reed switch, as shown in the image above.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Speed Measurement Code
&lt;/h2&gt;

&lt;p&gt;The code below can be used to get the average speed over a period of time and print it out. This is the initial version I’ve used to compare the results measured by the RPi and the original speed meter display, but as mentioned above, it measures the time between two falling edges and divides this by the determined conversion factor in order to get the current speed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import time
import RPi.GPIO as GPIO

BUTTON_GPIO = 18
# 1Hz is 2.2km/h
CONVERSION_FACTOR = 2.2

start = time.time()
# Used to calculate average speed
speeds = deque([0, 0, 0, 0, 0])

# Callback on the signal falling edge
def reed_switch_callback(channel):
    global start
    # Elapsed time between previous falling edge
    elapsed = time.time() - start
    start = time.time()
    
    speed = CONVERSION_FACTOR / elapsed

GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BUTTON_GPIO, GPIO.FALLING, callback=reed_switch_callback, bouncetime=10)

while True:

    no_activity = time.time() - start
    if no_activity &amp;gt; 1:
        # if there is no activity for more then 1s
        # this means we are bellow 2.2km/h so we add 0km/h measurement
        speeds.append(0)
        speeds.popleft()
    av_speed = sum(speeds) / len(speeds)

    print(f'average speed: {av_speed}')
    time.sleep(0.5)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Greengrass Setup
&lt;/h2&gt;

&lt;p&gt;Since I've been running this on a Raspberry Pi Zero W, before installing Greengrass I had to install &lt;code&gt;openjdk-8-jre&lt;/code&gt; as newer versions of java will not run on the ARMv6 instruction set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
sudo apt install openjdk-8-jre
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, I had to run the following on the device, while making sure I had AWS Credentials setup on the device before running it, as instructed &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/getting-started.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip &amp;gt; greengrass-nucleus-latest.zip &amp;amp;&amp;amp; unzip greengrass-nucleus-latest.zip -d GreengrassCore

export AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
export AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
export AWS_REGION="eu-west-1"
export GREENGRASS_THING_GROUP="home"
export GREENGRASS_THING_NAME="home-treadmill"

# For more: https://docs.aws.amazon.com/greengrass/v2/developerguide/getting-started.html#install-greengrass-v2
sudo -E java \
  -Droot="/greengrass/v2" \
  -Dlog.store=FILE -jar ./GreengrassCore/lib/Greengrass.jar \
  --aws-region ${AWS_REGION} \
  --thing-name ${GREENGRASS_THING_NAME} \
  --thing-group-name ${GREENGRASS_THING_GROUP} \
  --thing-policy-name GreengrassV2IoTThingPolicy \
  --tes-role-name GreengrassV2TokenExchangeRole \
  --tes-role-alias-name GreengrassCoreTokenExchangeRoleAlias \
  --component-default-user ggc_user:ggc_group \
  --provision true \
  --setup-system-service true \
  --deploy-dev-tools true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets up the Greengrass on the device with the appropriate Thing Group and Thing Name, in this scenario, &lt;code&gt;home&lt;/code&gt; and &lt;code&gt;home-treadmill&lt;/code&gt; respectively.&lt;br&gt;
As for the Greengrass components continuous deployment (CD) part where I use Github Actions, I’ve followed the instructions provided in the &lt;a href="https://devopstar.com/2022/09/22/github-actions-for-aws-iot-greengrass-v2-continuous-deployment" rel="noopener noreferrer"&gt;blog post&lt;/a&gt;, and extended the application to publish the speed measurements to the AWS IoT topic &lt;code&gt;home/treadmill/speed&lt;/code&gt; using the &lt;code&gt;awsiot.greengrasscoreipc.client&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The extended code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
import time
import traceback
import json

import signal
import sys
import RPi.GPIO as GPIO
import time
from collections import deque

import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import (
    IoTCoreMessage,
    QOS,
    PublishToIoTCoreRequest
)

BUTTON_GPIO = 18
# 1Hz is 2.2km/h
CONVERSION_FACTOR = 2.2

start = time.time()
# Used to calculate average speed
speeds = deque([0, 0, 0, 0, 0])

TIMEOUT = 10

ipc_client = awsiot.greengrasscoreipc.connect()

topic = "home/treadmill/speed"
qos = QOS.AT_MOST_ONCE

def signal_handler(sig, frame):
    GPIO.cleanup()
    sys.exit(0)

def reed_switch_callback(channel):
    global start
    # Elapsed time between previous falling edge
    elapsed = time.time() - start
    start = time.time()
    speed = CONVERSION_FACTOR / elapsed
    # Discard the noise as we can't measure speed above 36
    if speed &amp;lt; 36:
        speeds.append(speed)
        speeds.popleft()

GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_GPIO, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.add_event_detect(BUTTON_GPIO, GPIO.FALLING, callback=reed_switch_callback, bouncetime=10)

signal.signal(signal.SIGINT, signal_handler)
while True:
    no_activity = time.time() - start
    
    if no_activity &amp;gt; 1:
        # if there is no activity for more then 1s
        # this means we are bellow 2.2km/h so we add 0km/h measurement
        speeds.append(0)
        speeds.popleft()
    av_speed = sum(speeds) / len(speeds)
    if av_speed &amp;gt; 0:

        print(f'average speed: {av_speed}')

        request = PublishToIoTCoreRequest()
        request.topic_name = topic
        message = json.dumps({
            'time': time.time(),
            'speed': av_speed
        })
        request.payload = bytes(message, "utf-8")
        request.qos = qos
        operation = ipc_client.new_publish_to_iot_core()
        operation.activate(request)
        future_response = operation.get_response()
        future_response.result(TIMEOUT)        

    time.sleep(0.5)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, I’ve tried to compare my measurements back with the readings from the original speed meter display and got the same precession, which meant that even with the overhead of Greengrass, the system was running just fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using AWS IoT Rules
&lt;/h2&gt;

&lt;p&gt;In order to route the speed measurements coming from the device directly to the Timestream Database Table, I’ve used the AWS IoT Rules with the following select rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT speed FROM "home/treadmill/speed" WHERE speed&amp;gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and had the Amazon Timestream Database Table as an Action.&lt;br&gt;
This will interpret the values from a JSON payload message having &lt;code&gt;speed&lt;/code&gt; as a key and put the value in the selected Timestream table.&lt;/p&gt;

&lt;p&gt;Here is the Cloudformation stack that sets this up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSTemplateFormatVersion: '2010-09-09'
Resources:
  HomeTreadmillRule:
    Type: AWS::IoT::TopicRule
    Properties:
      RuleName: "HomeTreadmill"
      TopicRulePayload:
        RuleDisabled: false
        Sql: SELECT speed FROM "home/treadmill/speed" WHERE speed&amp;gt;0
        Actions:
        - Timestream:
            DatabaseName: "home-treadmill"
            TableName: "measurments"
            Dimensions: 
            - Name: "Speed"
              Value: 0
            RoleArn: !GetAtt HomeTreadmillTopicRuleRole.Arn
  HomeTreadmillDB:
    Type: AWS::Timestream::Database
    Properties: 
      DatabaseName: "home-treadmill"
  HomeTreadmillTable:
    Type: AWS::Timestream::Table
    Properties: 
      DatabaseName: !Ref HomeTreadmillDB
      RetentionProperties:
        MemoryStoreRetentionPeriodInHours: "24"
        MagneticStoreRetentionPeriodInDays: "7"
      TableName: "measurments"
  HomeTreadmillTopicRuleRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - iot.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: AllowTimestream
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - timestream:WriteRecords
                Resource:
                  - !GetAtt HomeTreadmillTable.Arn
              - Effect: Allow
                Action:
                  - timestream:DescribeEndpoints
                Resource: "*"    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation deploy --template-file cfn/amazon-timestream/timestream.yaml --stack-name home-treadmill-timestream --capabilities CAPABILITY_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Grafana Setup
&lt;/h2&gt;

&lt;p&gt;There are several ways to set up Grafana and use it to gain insights from Timestream table measurements; however, the simplest for me was to create a workspace using Amazon Managed Grafana.&lt;/p&gt;

&lt;p&gt;I intend to use it for other projects and give multiple users access to Grafana, which is part of my &lt;a href="https://docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html" rel="noopener noreferrer"&gt;AWS IAM Identity Center&lt;/a&gt;.&lt;br&gt;
To do this, I had to create a role that allows reading from the Timestream:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSTemplateFormatVersion: '2010-09-09'
Resources:
  AmazonGrafanaServiceRoleHomeTreadmill:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - grafana.amazonaws.com
            Action:
              - sts:AssumeRole
      ManagedPolicyArns: 
      - "arn:aws:iam::aws:policy/AmazonTimestreamReadOnlyAccess"
Outputs:
  RoleAwsAccountId:
    Value: !Ref AWS::AccountId
  RoleAwsRegion:
    Value: !Ref AWS::Region
  WorkspaceRoleToAssume:
    Value: !GetAtt AmazonGrafanaServiceRoleHomeTreadmill.Arn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with the deploy command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation deploy --template-file cfn/grafana/grafana-role.yaml --stack-name grafana-role --capabilities CAPABILITY_IAM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the get the Role ARN in order to use it to create a workspace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws cloudformation describe-stacks --stack-name grafana-role --query "Stacks[0].Outputs[0].OutputValue"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output looked something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"arn:aws:iam::&amp;lt;account id&amp;gt;:role/grafana-role-AmazonGrafanaServiceRoleHomeTreadmill-&amp;lt;id&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which I’ve used to create a Grafana workspace that is authenticated by AWS_SSO in the current account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws grafana create-workspace --account-access-type CURRENT_ACCOUNT --authentication-providers AWS_SSO --permission-type SERVICE_MANAGED --workspace-data-sources TIMESTREAM --workspace-role-arn &amp;lt;ARN from grafana-role stack&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that was done, I was able to see the new workspace and get the Grafana endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws grafana list-workspaces
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "workspaces": [
        {
            "authentication": {
                "providers": [
                    "AWS_SSO"
                ]
            },
            "created": "...",
            "description": "",
            "endpoint": "&amp;lt;id&amp;gt;.grafana-workspace.&amp;lt;region&amp;gt;.amazonaws.com",
            "grafanaVersion": "8.4",
            "id": "...",
            "modified": "...",
            "name": "home",
            "notificationDestinations": [],
            "status": "ACTIVE",
            "tags": {}
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, everything is preconfigured to create my dashboard, with Timestream as my source. The first panel is used to graph the &lt;strong&gt;speed&lt;/strong&gt; changes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jqziclhb6267dw6nf80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jqziclhb6267dw6nf80.png" alt="Grafana Speed" width="800" height="610"&gt;&lt;/a&gt;With the query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT time, measure_value::double as speed FROM $__database.$__table WHERE  measure_name='speed'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and other three to show &lt;strong&gt;Latest Speed:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT measure_value::double as speed FROM $__database.$__table ORDER BY time DESC LIMIT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Average Speed&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT AVG(measure_value::double) FROM $__database.$__table WHERE measure_name='speed'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Max Speed&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT MAX(measure_value::double) FROM $__database.$__table WHERE measure_name='speed'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the end goal looking like this:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfbdl3sod7ijened0xwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnfbdl3sod7ijened0xwe.png" alt="Grafana Dashboard" width="800" height="470"&gt;&lt;/a&gt;&lt;br&gt;
After running on my treadmill I can see the data coming in in real-time which will allow me to measure my progress and hopefully increase my maxim running speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion 
&lt;/h2&gt;

&lt;p&gt;As this started just as an inspiration from an IoT Builder Session I’m super happy how the whole process in setting this up lasted just couple of hours and at the end I got something that I’ll be using almost everyday. Additionally, having managed services to help me out on this journey meant I could have just focused on the RPi code and not worry about the complexity of the infrastructure.&lt;/p&gt;

&lt;p&gt;If you are interested in more info about the project, or want to try out something similar, take a look at the repo in our IoT Builders Github organisation: &lt;a href="https://github.com/aws-iot-builder-tools/ggv2-home-treadmill-example" rel="noopener noreferrer"&gt;https://github.com/aws-iot-builder-tools/ggv2-home-treadmill-example&lt;/a&gt;. As well as find a video that follows this blog here: &lt;a href="https://youtu.be/o6GhNFYXZKY" rel="noopener noreferrer"&gt;https://youtu.be/o6GhNFYXZKY&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally if you have questions, fell free to reach out on &lt;a href="https://www.linkedin.com/in/nenadilic84/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://twitter.com/nenadilic84" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>greengrass</category>
      <category>grafana</category>
      <category>raspberrypi</category>
      <category>iot</category>
    </item>
    <item>
      <title>Debugging C/C++ AWS IoT Greengrass Components using VSCode</title>
      <dc:creator>Nenad Ilic</dc:creator>
      <pubDate>Wed, 02 Nov 2022 08:49:53 +0000</pubDate>
      <link>https://dev.to/iotbuilders/debugging-cc-greengrass-components-using-vscode-1nbh</link>
      <guid>https://dev.to/iotbuilders/debugging-cc-greengrass-components-using-vscode-1nbh</guid>
      <description>&lt;p&gt;In most scenarios, simply logging the output of the application is enough to understand what is happening and perform debugging in case there is an application misbehaviour. However sometimes in order to catch some stubborn bugs stepping through the code while application is executing might be the most efficient way to do it. AWS IoT Greengrass provides a CLI tool that allows local components to be deployed and tested by also accessing the application logs, but in the scenario where we want to step through the code and understand the stack and other parts of the memory of a C/C++ component than we would need some additional configuration, which we will cover in this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;For this setup I will be using an EC2 instance running Ubuntu 22.04 and having tools like &lt;code&gt;gdb&lt;/code&gt;, &lt;code&gt;gdbserver&lt;/code&gt;,  &lt;code&gt;cmake&lt;/code&gt;  and &lt;code&gt;build-essential&lt;/code&gt; installed as well as having my VSCode configured for &lt;a href="https://code.visualstudio.com/docs/remote/ssh" rel="noopener noreferrer"&gt;Remote Development using SSH&lt;/a&gt;. For installing AWS IoT Greengrass, I’ll be using an installation instructions provided by a &lt;a href="https://docs.aws.amazon.com/greengrass/v2/developerguide/getting-started.html" rel="noopener noreferrer"&gt;Getting Started guide&lt;/a&gt;, but any variation of this that provides the tools mentioned above, as well as AWS IoT Greengrass and Greengrass CLI installed and running, should work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that for installing Greengrass CLI together with Greengrass, supply the installer with the parameter &lt;code&gt;--deploy-dev-tools true&lt;/code&gt; which will add the Greengrass CLI component.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Building and Running the C++ Application
&lt;/h2&gt;

&lt;p&gt;Before we can build our C++ we need to make sure the we have the AWS IoT Device SDK for C++ v2 build and available to link against as it provides the Greengrass IPC library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a workspace directory to hold all the SDK files
mkdir sdk-workspace
cd sdk-workspace
# Clone the repository
git clone --recursive https://github.com/aws/aws-iot-device-sdk-cpp-v2.git
# Ensure all submodules are properly updated
cd aws-iot-device-sdk-cpp-v2
git submodule update --init --recursive
cd ..
# Make a build directory for the SDK. Can use any name.
# If working with multiple SDKs, using a SDK-specific name is helpful.
mkdir aws-iot-device-sdk-cpp-v2-build
cd aws-iot-device-sdk-cpp-v2-build
# Generate the SDK build files.
# -DCMAKE_INSTALL_PREFIX needs to be the absolute/full path to the directory.
#     (Example: "/home/ubuntu/sdk-workspace/aws-iot-device-sdk-cpp-v2-build).
cmake -DCMAKE_INSTALL_PREFIX="/home/ubuntu/sdk-workspace/aws-iot-device-sdk-cpp-v2-build" ../aws-iot-device-sdk-cpp-v2
# Build and install the library. Once installed, you can develop with the SDK and run the samples
# -config can be "Release", "RelWithDebInfo", or "Debug"
cmake --build . --target install --config "Debug"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything builds successfully we can now go back and create our application directory and a C++ example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ../../
mkdir hello-world
cd hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In here let’s create a simple &lt;code&gt;CMakeLists.txt&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cmake_minimum_required(VERSION 3.1)
project (hello-world)

file(GLOB MAIN_SRC
        "*.h"
        "*.cpp"
        )
add_executable(${PROJECT_NAME} ${MAIN_SRC})

set_target_properties(${PROJECT_NAME} PROPERTIES
        LINKER_LANGUAGE CXX
        CXX_STANDARD 11)

find_package(aws-crt-cpp PATHS ~/sdk-workspace/aws-iot-device-sdk-cpp-v2-build)
find_package(EventstreamRpc-cpp PATHS ~/sdk-workspace/aws-iot-device-sdk-cpp-v2-build)
find_package(GreengrassIpc-cpp PATHS ~/sdk-workspace/aws-iot-device-sdk-cpp-v2-build)
target_link_libraries(${PROJECT_NAME} AWS::GreengrassIpc-cpp)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally let’s create our c++ example file which will subscribe to a specific MQTT topic (test/topic/cpp) and print out received messages &lt;code&gt;main.cpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;thread&amp;gt;

#include &amp;lt;aws/crt/Api.h&amp;gt;
#include &amp;lt;aws/greengrass/GreengrassCoreIpcClient.h&amp;gt;

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class IoTCoreResponseHandler : public SubscribeToIoTCoreStreamHandler {

    public:
        virtual ~IoTCoreResponseHandler() {}

    private:

        void OnStreamEvent(IoTCoreMessage *response) override {
            auto message = response-&amp;gt;GetMessage();
            if (message.has_value() &amp;amp;&amp;amp; message.value().GetPayload().has_value()) {
                auto messageBytes = message.value().GetPayload().value();
                std::string messageString(messageBytes.begin(), messageBytes.end());
                std::string messageTopic = message.value().GetTopicName().value().c_str();
                std::cout &amp;lt;&amp;lt; "Received new message on topic: " &amp;lt;&amp;lt; messageTopic &amp;lt;&amp;lt; std::endl;
                std::cout &amp;lt;&amp;lt; "Message: " &amp;lt;&amp;lt; messageString &amp;lt;&amp;lt; std::endl;
            }
        }

        bool OnStreamError(OperationError *error) override {
            std::cout &amp;lt;&amp;lt; "Received an operation error: ";
            if (error-&amp;gt;GetMessage().has_value()) {
                std::cout &amp;lt;&amp;lt; error-&amp;gt;GetMessage().value();
            }
            std::cout &amp;lt;&amp;lt; std::endl;
            return false; // Return true to close stream, false to keep stream open.
        }

        void OnStreamClosed() override {
            std::cout &amp;lt;&amp;lt; "Subscribe to IoT Core stream closed." &amp;lt;&amp;lt; std::endl;
        }
};

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        std::cout &amp;lt;&amp;lt; "OnConnectCallback" &amp;lt;&amp;lt; std::endl;
    }

    void OnDisconnectCallback(RpcError error) override {
        std::cout &amp;lt;&amp;lt; "OnDisconnectCallback: " &amp;lt;&amp;lt; error.StatusToString() &amp;lt;&amp;lt; std::endl;
        exit(-1);
    }

    bool OnErrorCallback(RpcError error) override {
        std::cout &amp;lt;&amp;lt; "OnErrorCallback: " &amp;lt;&amp;lt; error.StatusToString() &amp;lt;&amp;lt; std::endl;
        return true;
    }
};

int main() {
    String topic("test/topic/cpp");
    QOS qos = QOS_AT_LEAST_ONCE;
    int timeout = 10;

    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr &amp;lt;&amp;lt; "Failed to establish IPC connection: " &amp;lt;&amp;lt; connectionStatus.StatusToString() &amp;lt;&amp;lt; std::endl;
        exit(-1);
    }

    SubscribeToIoTCoreRequest request;
    request.SetTopicName(topic);
    request.SetQos(qos);
    auto streamHandler = MakeShared&amp;lt;IoTCoreResponseHandler&amp;gt;(DefaultAllocator());
    auto operation = ipcClient.NewSubscribeToIoTCore(streamHandler);
    auto activate = operation-&amp;gt;Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation-&amp;gt;GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr &amp;lt;&amp;lt; "Operation timed out while waiting for response from Greengrass Core." &amp;lt;&amp;lt; std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (response) {
        std::cout &amp;lt;&amp;lt; "Successfully subscribed to topic: " &amp;lt;&amp;lt; topic &amp;lt;&amp;lt; std::endl;
    } else {
        // An error occurred.
        std::cout &amp;lt;&amp;lt; "Failed to subscribe to topic: " &amp;lt;&amp;lt; topic &amp;lt;&amp;lt; std::endl;
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            std::cout &amp;lt;&amp;lt; "Operation error: " &amp;lt;&amp;lt; error-&amp;gt;GetMessage().value() &amp;lt;&amp;lt; std::endl;
        } else {
            std::cout &amp;lt;&amp;lt; "RPC error: " &amp;lt;&amp;lt; response.GetRpcError() &amp;lt;&amp;lt; std::endl;
        }
        exit(-1);
    }

    // Keep the main thread alive, or the process will exit.
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    operation-&amp;gt;Close();
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point we should be able to build the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir build
cd build
cmake -DCMAKE_PREFIX_PATH="/home/ubuntu/sdk-workspace/aws-iot-device-sdk-cpp-v2-build" -DCMAKE_BUILD_TYPE="Debug" ..
cmake --build . --config "Debug"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since this can work only in the context of Greengrass we need to prepare the component yaml file as well as the artifact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ..
mkdir -p gg/artifacts/com.example.HelloWorld/1.0.0
mkdir -p gg/recipes
touch gg/recipes/com.example.HelloWorld-1.0.0.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where the content of the &lt;code&gt;com.example.HelloWorld-1.0.0.yaml&lt;/code&gt; would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.HelloWorld
ComponentVersion: 1.0.0
ComponentDescription: My C++ component.
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        com.example.HelloWorld:mqttproxy:1:
          policyDescription: Allows access to subscribe to a topics.
          operations:
            - aws.greengrass#SubscribeToIoTCore
          resources:
            - "test/topic/cpp"
Manifests:
- Platform:
    os: linux
  Lifecycle:
    Run: "{artifacts:path}/hello-world"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can copy the &lt;code&gt;hello-world&lt;/code&gt; binary to artifacts directory and deploy the component to Greengrass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp build/hello-world gg/artifacts/com.example.HelloWorld/1.0.0/

sudo /greengrass/v2/bin/greengrass-cli deployment create \
  --recipeDir gg/recipes \
  --artifactDir gg/artifacts \
  --merge "com.example.HelloWorld=1.0.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this if look at the logs, we should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bash -c "cat /greengrass/v2/logs/com.example.HelloWorld.log"
...
com.example.HelloWorld: stdout. Successfully subscribed to topic: test/topic/cpp. {scriptName=services.com.example.HelloWorld.lifecycle.Run, serviceName=com.example.HelloWorld, currentState=RUNNING}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we verify that this is working properly, we can jump to the part where we actually do a step through debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging using GDB and VSCode
&lt;/h2&gt;

&lt;p&gt;First let’s set up our &lt;code&gt;.vscode/launch.json&lt;/code&gt; to use the &lt;code&gt;gdbserver&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "HelloWorld GG Component",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/hello-world/gg/artifacts/com.example.HelloWorld/1.0.0/hello-world",
            "miDebuggerServerAddress": "localhost:9091",
            "args": [],
            "stopAtEntry": true,
            "cwd": "${workspaceRoot}",
            "environment": [],
            "externalConsole": false,
            "serverStarted": "Listening on port",
            "filterStderr": true,
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "enable-pretty-printing",
                    "ignoreFailures": true,
                }
            ],
            "MIMode": "gdb",
        }
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this is a typical configuration two things we need to make sure are set right. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;program&lt;/code&gt; is pointing to where the actual artifact is being installed by the Greengrass CLI, &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;miDebuggerServerAddress&lt;/code&gt; is set to right host and port. In this scenario since we are doing this locally we will be using the &lt;code&gt;localhost&lt;/code&gt; and port of choice is &lt;code&gt;9091&lt;/code&gt; which we need to match when modifying the Greengrass component recipe.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next we will instruct Greengrass to start the &lt;code&gt;gdbserver&lt;/code&gt; when starting the component, which will allow us to use &lt;code&gt;gdb&lt;/code&gt; for remote debugging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.HelloWorld
ComponentVersion: 1.0.0
ComponentDescription: My C++ component.
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        com.example.HelloWorld:mqttproxy:1:
          policyDescription: Allows access to subscribe to a topics.
          operations:
            - aws.greengrass#SubscribeToIoTCore
          resources:
            - "test/topic/cpp"
Manifests:
- Platform:
    os: linux
  Lifecycle:
    Run: "gdbserver :9091 {artifacts:path}/hello-world"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here the only difference is the &lt;code&gt;Run&lt;/code&gt; command which we prefixed with &lt;code&gt;gdbserver :9091&lt;/code&gt;. After this is done we can redeploy the component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo /greengrass/v2/bin/greengrass-cli deployment create \
  --recipeDir gg/recipes \
  --artifactDir gg/artifacts \
  --merge "com.example.HelloWorld=1.0.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After which we should see the following in the component logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bash -c "cat /greengrass/v2/logs/com.example.HelloWorld.log"
com.example.HelloWorld: stderr. Listening on port 9091. {scriptName=services.com.example.HelloWorld.lifecycle.Run, serviceName=com.example.HelloWorld, currentState=RUNNING}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, we can just create a breakpoint and start the debugging session:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp62u5r9tulusgb7fx1um.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp62u5r9tulusgb7fx1um.png" alt="VSCode Debug Main"&gt;&lt;/a&gt;&lt;br&gt;
We can then put a break point at line 19, which we will let us stop the application upon a retrieval of a message from the AWS IoT Core. &lt;br&gt;
In order to test this we can go to AWS console → AWS IoT Core → MQTT test client → Publish to a topic and publish a message to the &lt;code&gt;test/topic/cpp&lt;/code&gt; like the example bellow.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8r902e9ptyu5p1qn7tg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8r902e9ptyu5p1qn7tg.png" alt="AWS IoT MQTT Client Test"&gt;&lt;/a&gt;&lt;br&gt;
We will be able to catch this with the breakpoint and step through if necessary.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcc6pxu52xunbyt9t3duq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcc6pxu52xunbyt9t3duq.png" alt="VSCode Debug"&gt;&lt;/a&gt;&lt;br&gt;
Additionally after the message got received and processed we will see it in the component log as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This setup allows us to use &lt;code&gt;gdbserver&lt;/code&gt; / &lt;code&gt;gdb&lt;/code&gt; and VSCode to visualise and inspect what is happening in our GGv2 components. We can go further and even debug multiple components at the same time, where the only thing we need to change would be the &lt;code&gt;gdbserver&lt;/code&gt; ports on which those applications are running and modify it in the recipe respectively.&lt;/p&gt;

&lt;p&gt;If you find this interesting or have suggestions for future topics feel free to reach out here or @nenadilc84 on &lt;a href="https://twitter.com/nenadilic84" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/nenadilic84/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is also a &lt;a href="https://youtu.be/qMNZJ0CHZ9U" rel="noopener noreferrer"&gt;video&lt;/a&gt; version of this blog&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>iot</category>
      <category>greengrass</category>
    </item>
  </channel>
</rss>
