<?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: Alina Dima</title>
    <description>The latest articles on DEV Community by Alina Dima (@fay_ette).</description>
    <link>https://dev.to/fay_ette</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%2F934452%2Fc6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg</url>
      <title>DEV Community: Alina Dima</title>
      <link>https://dev.to/fay_ette</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fay_ette"/>
    <language>en</language>
    <item>
      <title>A Tool to Validate AWS IoT Rules SQL Statements</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Wed, 12 Jul 2023 15:22:45 +0000</pubDate>
      <link>https://dev.to/iotbuilders/a-tool-to-validate-aws-iot-rules-sql-statements-jg</link>
      <guid>https://dev.to/iotbuilders/a-tool-to-validate-aws-iot-rules-sql-statements-jg</guid>
      <description>&lt;p&gt;Rules Engine is a feature in AWS IoT Core that allows engineers to filter, decode, and process IoT device data and route this data to 15+ AWS and third-party services. AWS IoT Core Rules Engine currently has support for over 70 distinct SQL functions which can be used in either SELECT or WHERE clauses, 14 distinct operators which can be used in either SELECT or WHERE clauses, all JSON data types, specifying Literal objects in the SELECT and WHERE clauses, case statements, JSON extensions, substitution templates and nested object queries and more.  &lt;/p&gt;

&lt;p&gt;In this post, we explore how to validate AWS IoT Core Rules Engine Rules SQL Statements, by introducing a validation tool which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Encapsulates the heavy lifting of creating, configuring and cleaning up the AWS resources needed to create, run and validate IoT Rule SQL payload transformations.&lt;/li&gt;
&lt;li&gt;Enables friction free validation of Rules syntax and payload transformations.&lt;/li&gt;
&lt;li&gt;Provides an easily extensible library of sample SQL statements, with input payloads and expected output, allowing you to build your own use-cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This tool is available on GitHub, &lt;a href="https://github.com/aws-iot-builder-tools/validation-tool-for-aws-iot-rules/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do we need a tool?
&lt;/h2&gt;

&lt;p&gt;To validate SQL syntax and the input/output expectations, developers would normally need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a rule.&lt;/li&gt;
&lt;li&gt;Create and assign actions to the rule.&lt;/li&gt;
&lt;li&gt;Create and assign an IAM Role with valid permissions for the actions.&lt;/li&gt;
&lt;li&gt;Subscribe to the output topic (or monitor the output system), and then publish an MQTT message, to see if the rule works. &lt;/li&gt;
&lt;li&gt;If the Rule execution does not work, they have to check in Amazon CloudWatch IoT Logs or the downstream service logs to see what went wrong. &lt;/li&gt;
&lt;li&gt;If Amazon CloudWatch Logs for IoT are not enabled, developers need to enable them and then try again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is quite some heavy lifting, if the ultimate purpose is to validate that the payload transformations from provided input into expected output work as expected. &lt;/p&gt;

&lt;p&gt;So this called for creating a tool that enables developers to do a ‘closed box ’- type of validation, where input payload, SQL statement and expected output are provided. The tool executes validation scenarios, and if the Rules Engine parses the input as expected, with the expected output, scenarios succeed, if not they fail and expected versus actual output payload are printed for references. &lt;/p&gt;

&lt;h2&gt;
  
  
  How does the tool work?
&lt;/h2&gt;

&lt;p&gt;The diagram below shows the architecture of the validation tool. You can imagine this tool working like an integration test suite, where you only need to define the inputs, configuration and expected outputs (components you need to define are marked yellow). This inputs are provided as a new JSON file and also referred to as creating a new test case or validation scenario. See the &lt;em&gt;“Adding a new test case”&lt;/em&gt; section below for details.&lt;/p&gt;

&lt;p&gt;The integration test itself (set-up, execution, assertions and expectations and tear down - marked gray on the diagram)  is already part of the tool. Of course, if you discover that you need to implement different behaviour to the one the tool provides for set up/tear down/test execution and assertions/validation, you can extend this tool by creating further integration tests to fit your use case. &lt;/p&gt;

&lt;p&gt;Additionally, the tool also includes a sample library with validation scenarios, comprised to date, of 6 examples from the more popularly reported Rules SQL statement questions. These scenarios can be explored, executed or modified and adapted.  &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%2Fyoymejjootnvr8yc21gc.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%2Fyoymejjootnvr8yc21gc.png" alt="Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To better understand the format of the input, have a look at the current JSON schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "type": "object",
  "properties": {
    "sqlVersion": {
      "type": "string",
      "description": "SQL version needed for the test. Defaults to latest."
    },
    "topic": {
      "type": "string",
      "description":"This is the AWS IoT MQTT topic that the input payload will be published on. The same topic must be used in the Rule SQL FROM clause. "
    },
    "inputPayload": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "object"
        }
      ],
      "description":"This is the test input payload which will be published during the test execution. "
    },
    "inputSql": {
      "type": "string",
      "description":"This is the SQL statement of the IoT Rule under evaluation. "
    },
    "expectedOutput": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "object"
        },
        {
          "type": "array"
        }
      ]
    },
    "description":"This is the expected output that the input payload will be transformed into after scenario validation execution. "

  },
  "required": [
    "topic",
    "inputPayload",
    "inputSql",
    "expectedOutput"
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Pre-Requisites
&lt;/h3&gt;

&lt;p&gt;To be able to run the existing or new validation scenarios, you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;a href="https://docs.npmjs.com/getting-started" rel="noopener noreferrer"&gt;npm&lt;/a&gt;. This project was tested with Node v18.16.0.&lt;/li&gt;
&lt;li&gt;Have an AWS Account and provide Node.js with &lt;a href="https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/setting-credentials-node.html" rel="noopener noreferrer"&gt;credentials&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Repository Structure
&lt;/h3&gt;

&lt;p&gt;The project repository is structured as per screenshot below: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;util&lt;/code&gt; folder containing the configuration, environment and resource set-up  and clean-up utilities. The utilities are called from the validation test automatically as needed.&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;validation&lt;/code&gt; folder containing:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;validation-data&lt;/code&gt;: this is a sample library of working examples of SQL statements which validate successfully. You can extend this folder with more validation scenario files as needed. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;input-json-schema&lt;/code&gt;: providing type and description information for mandatory and optional input fields. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;validate-iot-rules&lt;/code&gt;: which is the framework for set up and execution of the provided and new validation scenarios. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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%2Fvrp2npvkbztozh4mqcmq.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%2Fvrp2npvkbztozh4mqcmq.png" alt="Repo structure"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  To get started
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Clone the GitHub repository: &lt;a href="https://github.com/aws-iot-builder-tools/validation-tool-for-aws-iot-rules" rel="noopener noreferrer"&gt;https://github.com/aws-iot-builder-tools/validation-tool-for-aws-iot-rules&lt;/a&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure you add your AWS account id in the configuration file: &lt;code&gt;util/config.js&lt;/code&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run:&lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By default, the default validation scenario is executed: &lt;code&gt;casting-sensor-payload.json&lt;/code&gt;.  To run the default scenario, run:  &lt;code&gt;npm run test&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To change the default scenario, got to &lt;code&gt;config.js&lt;/code&gt;, and re-set the &lt;code&gt;defaultInputFile&lt;/code&gt; to a file of your choice from the provided files in the &lt;code&gt;validation/validation-data&lt;/code&gt; directory. You can choose the validation scenario you want to execute, by running: &lt;code&gt;npm test -- -inputFile=&amp;lt;existing or newly created file name&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can also choose to execute all the provides scenarios, by running: &lt;code&gt;npm test -- -inputFile=ALL&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Note that:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is a development tool, which is designed to support with faster, friction free testing and validation of SQL statements based on desired inputs and outputs. It is therefore not recommended to run this tool against production environments.&lt;/li&gt;
&lt;li&gt;Running all validation scenarios takes longer as, the tool creates and needed rules, IAM roles and policies before executing any of the tests. &lt;/li&gt;
&lt;li&gt;As tests are executed, expectations are evaluated to either success or failure (with the printed expected and actual result). &lt;/li&gt;
&lt;li&gt;All AWS resources are automatically cleaned up post execution, so there is no manual action needed. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there is a test failure, you see the comparison between expected and actual output, as shown below: &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%2F2yxnx5uwsncwf7pi6l91.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%2F2yxnx5uwsncwf7pi6l91.png" alt="Example Failure"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Adding a new validation scenario
&lt;/h2&gt;

&lt;p&gt;Adding a new validation scenario based on your use-case is straight-forward. You need to add a new JSON file in the &lt;code&gt;verification-tool-for-aws-iot-rules/validation/validation-data&lt;/code&gt;folder. &lt;/p&gt;

&lt;p&gt;The following requirements hold when adding your own new validation scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The contents of the file must follow the JSON schema (&lt;code&gt;validation/input-json-schema.json&lt;/code&gt;) mentioned in the paragraph above and include all mandatory fields, with the correct data types.
&lt;/li&gt;
&lt;li&gt;You need to also make sure that the topic name is test uses is unique. &lt;/li&gt;
&lt;li&gt;If you add more validation scenarios, bear in mind that you might need to adjust the Jest timeout value. If you want to execute all validation scenarios together in the same test suite after you added more scenarios, you should adjust the timeout value in the test itself, or in the Jest configuration (&lt;code&gt;jest.config.js&lt;/code&gt;). &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Conclusion and Future Improvements
&lt;/h2&gt;

&lt;p&gt;This blog shows an approach which allows developers to experiment with and validate AWS IoT Rules SQL statements faster and friction-free. This is achieved by encapsulating the complexities of AWS resource creation and clean-up, publishing data on topics and republishing actions in a configurable and extensible tool developers can use (&lt;a href="https://github.com/aws-iot-builder-tools/validation-tool-for-aws-iot-rules" rel="noopener noreferrer"&gt;available on GitHub&lt;/a&gt;), which does this heavy lifting. &lt;/p&gt;

&lt;p&gt;This tool is currently in its first iteration. Below is a list of improvements could be considered for future iterations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the current version, the tool is designed to run locally. Ideally it would be integrated in a CI/CD pipeline.&lt;/li&gt;
&lt;li&gt;Add support for MQTT 5 and protobuf.&lt;/li&gt;
&lt;li&gt;Add ability to mock Rules SQL functions which call other AWS and Amazon services, like Amazon DynamoDB or AWS Lambda.&lt;/li&gt;
&lt;li&gt;In the current version, the tool assumes that the rule executes (i.e. that the payload satisfies the WHERE clause). To validate scenarios where input payloads do not satisfy the WHERE clause, a new test case needs to be created, with modified expectations.&lt;/li&gt;
&lt;li&gt;Improve overall execution time and resilience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information about AWS IoT Core and Rules Engine, have a look at the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html" rel="noopener noreferrer"&gt;AWS IoT Developer Guide&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you have validation scenarios you would like to share, or additions to this tool, feel free reach out to me on &lt;a href="https://www.linkedin.com/in/alina-dima/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://twitter.com/fay_ette" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;, or provide feedback on GitHub. &lt;/p&gt;

&lt;p&gt;To get notified about more IoT content, you can additionally subscribe to the &lt;a href="https://www.youtube.com/@iotbuilders" rel="noopener noreferrer"&gt;IoT Builders YouTube channel&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Author&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;


&lt;div class="ltag__user ltag__user__id__934452"&gt;
    &lt;a href="/fay_ette" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F934452%2Fc6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg" alt="fay_ette image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/fay_ette"&gt;Alina Dima&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/fay_ette"&gt;An engineer for about 20 years, love solving real world problems with code. I simplify complex problems to help developer communities build better and faster with AWS IoT. &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>iot</category>
      <category>awsiot</category>
      <category>testing</category>
    </item>
    <item>
      <title>Batch Ingestion of IoT Device Metrics into Amazon CloudWatch Metrics, using Embedded Metric Format (EMF)</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Thu, 22 Jun 2023 10:37:34 +0000</pubDate>
      <link>https://dev.to/iotbuilders/batch-ingestion-of-iot-device-metrics-into-amazon-cloudwatch-metrics-using-embedded-metric-format-emf-3o6b</link>
      <guid>https://dev.to/iotbuilders/batch-ingestion-of-iot-device-metrics-into-amazon-cloudwatch-metrics-using-embedded-metric-format-emf-3o6b</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This blog demonstrates how to generate, ingest, store and vizualize IoT device metrics by using the Embedded Metric Format (&lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Specification.html"&gt;EMF&lt;/a&gt;) and native integrations between AWS IoT Core Rules Engine and Amazon CloudWatch, as well as CloudWatch Logs and Metrics. The Amazon CloudWatch Embedded Metric Format is a JSON specification used to instruct Amazon CloudWatch Logs to automatically extract metric values embedded in structured log events. &lt;/p&gt;

&lt;p&gt;In this post, we will see how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ingest metric values embedded in structured log events in batch mode via the AWS IoT Core Rules Engine and the Basic Ingest feature. &lt;/li&gt;
&lt;li&gt;Store these log events in Amazon CloudWatch.&lt;/li&gt;
&lt;li&gt;View the metrics in Amazon CloudWatch Metrics and create graphs on the extracted metric values.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a detailed walk-through a live demo of this solution, you can watch the video linked below on the &lt;a href="https://www.youtube.com/@iotbuilders"&gt;IoT Builders YouTube channel&lt;/a&gt;:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Batch Ingestion of IoT Device Metrics into Amazon CloudWatch Metrics&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/d0hauFXRkok"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of this Approach
&lt;/h2&gt;

&lt;p&gt;The benefit of using Basic Ingest is optimizing the data flow by removing the AWS IoT Core MQTT Broker from the ingestion path, thus removing the messaging costs. &lt;/p&gt;

&lt;p&gt;On the device-side, sending metrics in batches is more efficient and caters for temporary connectivity loss. The EMF timestamps ensure that metrics are stored in an eventually consistent manner.  The integration between AWS IoT Rules Engine and Amazon CloudWatch happens via a Rules Action, therefore reducing the need for bespoke code. Another  benefit of this approach is that Amazon CloudWatch automatically extracts the metrics from logs.&lt;/p&gt;

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

&lt;p&gt;In this post, we will walk through the steps to generate IoT device metrics in the EMF format, like system or OS information at a sampling interval, batch them and ingest them using Basic Ingest, at a chosen reporting interval. This means that metrics are consolidated and sent in batches (independently of the collection time), instead of being routed event by event (one-by-one as they occur). &lt;/p&gt;

&lt;p&gt;Once the batched metrics arrive at the IoT Rule, they are routed to Amazon CloudWatch using &lt;code&gt;batchMode&lt;/code&gt;. &lt;code&gt;batchMode&lt;/code&gt; is a Boolean parameter within the AWS IoT CloudWatch Logs rule action. This parameter is optional and is off (false) by default. To upload device-side log files in batches, you must turn this parameter on (true) when you create the AWS IoT rule.  &lt;/p&gt;

&lt;p&gt;Because the logs follow the EMF specification, Amazon CloudWatch automatically extracts the metric values embedded in structured log events, and we can create graphs and alarms on the extracted metric values. &lt;/p&gt;

&lt;p&gt;The diagram below shows the ingestion flow: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7RbxhnjD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jw9y9lqxtfxm4wl9yiso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7RbxhnjD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jw9y9lqxtfxm4wl9yiso.png" alt="IoT Metrics Ingestion" width="800" height="763"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Set-up
&lt;/h2&gt;

&lt;p&gt;To run this demo, clone the repo: &lt;a href="https://github.com/aws-iot-builder-tools/emf-metrics-with-iot-rules"&gt;https://github.com/aws-iot-builder-tools/emf-metrics-with-iot-rules&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository is composed of two folders: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app&lt;/code&gt; - containing the application code and configuration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;infra&lt;/code&gt; - containing the infrastructure CDK code and configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will need both to set up the demo. &lt;/p&gt;

&lt;p&gt;To run the demo, the following steps should be performed:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Deploy the required AWS resources:
&lt;/h3&gt;

&lt;p&gt;The AWS resources for this demo are created and deployed using AWS CDK. The CDK Typescript code creates and deploys: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An IoT device policy, allowing the device to connect to AWS IoT Core and publish data on the Basic Ingest Rule topic. This policy looks as below:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "iot:Connect"
      ],
      "Resource": [
        "arn:aws:iot:&amp;lt;AWS_REGION&amp;gt;:&amp;lt;AWS_ACCOUNT&amp;gt;:client/${iot:ClientId}"
      ],
      "Effect": "Allow"
    },
    {
      "Action": [
        "iot:Publish"
      ],
      "Resource": [
        "arn:aws:iot:&amp;lt;AWS_REGION&amp;gt;:&amp;lt;AWS_ACCOUNT&amp;gt;:topic/$aws/rules/emf/${iot:ClientId}/logs"
      ],
      "Effect": "Allow"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;An IoT Rule for Basic Ingest, configured with an action to batch ingest log entries into Amazon CloudWatch.&lt;/li&gt;
&lt;li&gt;An IAM Role with the correct IAM policy allowing the IoT Rule to ingest into CloudWatch. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pre-requisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must have AWS CDK installed and configured with the required credentials for your AWS Account. For help with this, follow the steps in the &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-typescript.html"&gt;documentation&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the &lt;code&gt;infra&lt;/code&gt;  directory , run &lt;code&gt;npm run build&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;cdk deploy&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  2. Run the IoT Device Simulation Application:
&lt;/h3&gt;

&lt;p&gt;The IoT application connects to AWS IoT Core using an MQTT client implemented with &lt;a href="https://github.com/mqttjs"&gt;MQTT.Js&lt;/a&gt;, reads operating system metrics on a sampling interval of 5 seconds, stores them in an in-memory array and ingests them in batches at a reporting interval of 15 seconds. In the &lt;code&gt;app&lt;/code&gt; folder, there is also a utility function which, in an idempotent manner, creates the IoT thing, certificate and keys.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-requisites:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To run the IoT application, you need to ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That your application has the correct credentials to make calls to AWS IoT to create the IoT thing, certificate and keys (More info &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;That the correct &lt;code&gt;AWS Region&lt;/code&gt; is also configured. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fill in &lt;code&gt;config.js&lt;/code&gt; with your IoT endpoint configuration:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const config = {
    iotEndpoint: "&amp;lt;YOUR_AWS_IOT_ENDPOINT&amp;gt;",
    region: "&amp;lt;YOUR_AWS_REGION&amp;gt;"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;npm install&lt;/code&gt; in the &lt;code&gt;app&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;node app.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Metrics Format and Ingestion
&lt;/h2&gt;

&lt;p&gt;On the device, metric values are embedded in structured log events, so that Amazon CloudWatch can automatically extract them. In the example, memory metrics and network metrics are stored in 2 different namespaces &lt;code&gt;iot-device-memory&lt;/code&gt; and &lt;code&gt;iot-device-network&lt;/code&gt;. The format looks as follows:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const statObject = {
    "_aws": {
        "Timestamp": Date.now(),
        "CloudWatchMetrics": [
            {
                "Namespace": "iot-device-memory",
                "Dimensions": [["thingName"]],
                "Metrics": [
                    {
                        "Name": "total",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "free",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "used",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "active",
                        "Unit": "Kb",
                        "StorageResolution": 60
                    }, {
                        "Name": "available",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    },
                ]
            },
            {
                "Namespace": "iot-device-network",
                "Dimensions": [["thingName"]],
                "Metrics": [
                    {
                        "Name": "operstate",
                         "Unit": "String",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "rx_bytes",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "rx_dropped",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "rx_errors",
                        "Unit": "Count",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "tx_bytes",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    }, {
                        "Name": "tx_dropped",
                        "Unit": "Kb",
                        "StorageResolution": 1
                    },
                    {
                        "Name": "tx_errors",
                        "Unit": "Count",
                        "StorageResolution": 1
                    }, {
                        "Name": "ms",
                        "Unit": "Milliseconds",
                        "StorageResolution": 1
                    },
                ]
            }
        ]
    },
    "thingName": CLIENT_ID,
    "total": convertSize(memory.total, "KB"),
    "free": convertSize(memory.free,"KB"),
    "used": convertSize(memory.used,"KB"),
    "active": convertSize(memory.active,"KB"),
    "available": convertSize(memory.available,"KB"),
    "iface": iface,
    "operstate": network_0.operstate,
    "rx_bytes": convertSize(network_0.rx_bytes,"KB"),
    "rx_dropped": convertSize(network_0.rx_dropped,"KB"),
    "rx_errors": network_0.rx_errors,
    "tx_bytes": convertSize(network_0.tx_bytes,"KB"),
    "tx_dropped": convertSize(network_0.tx_dropped,"KB"),
    "tx_errors": network_0.tx_errors,
    "ms": network_0.ms,
    "requestId": v4()
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;"convert-size"&lt;/code&gt; JavaScript library is used to convert from bytes to kilobytes.  Every 5 seconds (as configured via the sampling interval), a new entry is collected in the &lt;code&gt;statsObject&lt;/code&gt;, and added to an in-memory array. Every 15 seconds (as configured by the reporting interval), a batch object is constructed containing the array, and this object is published into the Basic Ingest IoT Rule Topic, as below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let message = {
                batch: []
            }
            metrics.forEach(metric =&amp;gt; {
                message.batch.push(
                    {"timestamp": Date.now(), "message": JSON.stringify(metric)});
            })
&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;client.publish(METRICS_PUB_TOPIC, JSON.stringify(message), {
                qos: 1,
                properties: {
                    contentType: 'application/json',
                    correlationData: JSON.stringify({messageId: messageId, appId: appId})
                }
            });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On the AWS cloud-side, an IoT Rule is created as per CDK code below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new CfnTopicRule(this, 'BasicIngestEMFIoTRule', {
            ruleName: 'emf',
            topicRulePayload: {
                actions: [
                    {
                        cloudwatchLogs: {
                            logGroupName: LOG_GROUP_NAME,
                            roleArn: CWRole.roleArn,
                            batchMode: true,
                        }
                    }
                ],
                description: 'IoT Rule',
                sql: `SELECT VALUE *.batch
                      FROM '${METRICS_RULE_TOPIC}'`,
                ruleDisabled: false,
                awsIotSqlVersion: '2016-03-23'
            }
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The video below shows the application log for storing and publishing the metrics in batches:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S_gBoXQ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnf8g765x0951e911gv9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S_gBoXQ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnf8g765x0951e911gv9.gif" alt="EMF generation IoT" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Amazon CloudWatch Logs and CloudWatch Metrics
&lt;/h2&gt;

&lt;p&gt;Upon batch ingestion, each item in the batch will be stored as a separate entry in CloudWatch logs. Because the format used is EMF, the metrics are extracted by Amazon CloudWatch and available in CloudWatch Metrics to create charts and alarms. Below is a video of how the log entries look with the LiveTail view: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PnKo5Bcw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2w50y3w8zqpmzdm7d9ug.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PnKo5Bcw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2w50y3w8zqpmzdm7d9ug.gif" alt="Tail CW" width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each element in the batch sent from the IoT device is stored as a separate log entry, with the correct reporting timestamped passed from the device. The sampling timestamps for the metrics become relevant when the metrics are extracted. Below is a log entry view from the LiveTail:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cfBMrGuu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o0tef3jjb2sdly34vafq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cfBMrGuu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o0tef3jjb2sdly34vafq.png" alt="LiveTail view" width="800" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigating to Amazon CloudWatch Metrics, you can see the two newly created namespaces with thing name as the dimension. By clicking one of the namespaces, you can plot the metrics values over time, with the desired aggregations, as shown in the video below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mdBV_nPZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0arct4rfviqug6e10mo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mdBV_nPZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w0arct4rfviqug6e10mo.gif" alt="Metrics Graphs" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this post, we looked at how to leverage Basic Ingest and the AWS IoT CloudWatch Logs Action in Batch Mode, in order to ingest and route device metrics in &lt;code&gt;EMF&lt;/code&gt; format. The benefit of this approach is that Amazon CloudWatch automatically extracts the metrics from logs. Additionally, ingestion costs are reduced by using Basic Ingest. In case of temporary loss of connectivity, the batching functionality will ensure eventual data consistency.&lt;/p&gt;

&lt;p&gt;Once the metrics are in the cloud, they can be viewed in CloudWatch metrics, to prepare charts or set alarms. For more information on uploading IoT device logs to Amazon CloudWatch, have a look at the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/upload-device-logs-to-cloudwatch.html"&gt;developer documentation&lt;/a&gt;. To learn more about EMF, check the &lt;a href="https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Specification.html"&gt;specification&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;To get notified about more IoT content, you can additionally subscribe to the &lt;a href="https://www.youtube.com/@iotbuilders"&gt;IoT Builders YouTube channel&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Author&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;


&lt;div class="ltag__user ltag__user__id__934452"&gt;
    &lt;a href="/fay_ette" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fgnop5T5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/practicaldev/image/fetch/s--ZqZiFyKC--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/934452/c6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg" alt="fay_ette image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/fay_ette"&gt;Alina Dima&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/fay_ette"&gt;An engineer for about 20 years, love solving real world problems with code. I simplify complex problems to help developer communities build better and faster with AWS IoT. &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Enriching Payloads with MQTT 5 Metadata, using AWS IoT Core Rules Engine</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Thu, 08 Jun 2023 13:18:13 +0000</pubDate>
      <link>https://dev.to/iotbuilders/enriching-payloads-with-mqtt-5-metadata-using-aws-iot-core-rules-engine-4oh</link>
      <guid>https://dev.to/iotbuilders/enriching-payloads-with-mqtt-5-metadata-using-aws-iot-core-rules-engine-4oh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This blog post explains how to build a Vehicle Command Log Store to keep track of command requests and responses sent to vehicles by application clients. To this purpose, we look at extracting MQTT 5 metadata information from MQTT messages published using MQTT v5, and enrich payloads via an AWS IoT Core Rules Engine Rules. Processed data is stored in an Amazon DynamoDB table.&lt;/p&gt;

&lt;p&gt;The goal is to use as little bespoke code on the cloud side as possible and lean on native integrations on the AWS Cloud side, like the IoT Rule with Dynamo DB Action.  &lt;/p&gt;

&lt;p&gt;For a detailed walk-through a live demo of this solution, you can watch the video linked below on the &lt;a href="https://www.youtube.com/@iotbuilders" rel="noopener noreferrer"&gt;IoT Builders YouTube channel&lt;/a&gt;:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Enriching Payloads with MQTT 5 Metadata&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/acUzYWCYK0M"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  MQTT 5 Request/Response Pattern
&lt;/h2&gt;

&lt;p&gt;As part of this blog post, we exploring a feature of MQTT 5: the &lt;code&gt;Request/Response pattern&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The Request/Response messaging pattern is a method to track responses to client requests in an asynchronous way. It’s a mechanism implemented in MQTTv5 to allow the publisher to specify a topic for the response to be sent on a particular request. When the subscriber receives the request, it also receives the topic to send the response on. This pattern supports a correlation data field that allows tracking of packets, e.g. request or device identification parameters.&lt;/p&gt;

&lt;p&gt;Let's look at an example: &lt;/p&gt;

&lt;p&gt;We want to send commands to vehicles over MQTT from client applications. The flow is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Vehicles subscribe to the request topic, and client applications subscribe to their decided response topics, which can be dependent on the application instance id, for example.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;App clients publish requests on the request topic. In our case, the payload is a simple text &lt;code&gt;DOOR_LOCK&lt;/code&gt; indicating the command to lock the vehicle doors. Following the MQTT 5 pattern, in addition to the payload, we are sending metadata like the &lt;code&gt;Response Topic&lt;/code&gt;, &lt;code&gt;Content Type&lt;/code&gt; and &lt;code&gt;Correlation Data&lt;/code&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;request id&lt;/code&gt;, &lt;/li&gt;
&lt;li&gt;a &lt;code&gt;timestamp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;user id&lt;/code&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This data helps correlate MQTT requests and their responses. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;As the device receives the MQTT message, it executes the command and publishes the response on the specified response topic. Upon publishing, it re-send the correlation data, but also appends response specific information, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;response timestamp&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;command&lt;/code&gt; it is responding to, 
marked red on the diagram.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The app instance receives this information on the response topic it subscribed to previously. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&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%2F37hsgcrgulwurxwzb5qw.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%2F37hsgcrgulwurxwzb5qw.png" alt="MQTT 5 Example Flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites and Approach
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To recreate this demo locally, one needs to already have in place:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS Account with permissions to create IoT resources.&lt;/li&gt;
&lt;li&gt;Two created AWS IoT things for the app and car simulators, with locally stored certificates and keys to connect to AWS IoT Core.&lt;/li&gt;
&lt;li&gt;An IoT Core policy allowing connections, subscriptions and data publishing for both IoT Things on the configured topics.&lt;/li&gt;
&lt;li&gt;An Amazon DynamoDB table needs to be created beforehand, with a unique identifier ‘msgId’ string as primary key. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This section looks at the steps to be performed: &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1:  Setting up the the MQTTJS clients
&lt;/h3&gt;

&lt;p&gt;First, we build two client simulators, for the car and the application client. We use &lt;a href="https://github.com/mqttjs/MQTT.js/" rel="noopener noreferrer"&gt;MQTTJS for Javascript&lt;/a&gt; and its MQTT v5 implementation support.  Step 1 below will describe the details of the MQTT client implementation. &lt;/p&gt;

&lt;p&gt;Upon running the application simulator, it connects, subscribes to the response topic and stays connected. Every 10 seconds, the application simulator publishes a &lt;code&gt;DOOR_LOCK&lt;/code&gt; text message command. Upon running the car simulator, it connects and stays connected, then receives a command from the app client, simulates its execution with a JavaScript timer and sends back a  &lt;code&gt;DOOR_LOCK_SUCCESS&lt;/code&gt; response. &lt;/p&gt;

&lt;p&gt;The MQTT Request/Response pattern implementation is exemplified in the code snippets below:&lt;/p&gt;

&lt;h4&gt;
  
  
  Car Simulator
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Connection options and connection creation:&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;//create options for MQTT v5 client
        const options = {
            clientId: CLIENT_ID,
            host: ENDPOINT,
            port: PORT,
            protocol: 'mqtts',
            protocolVersion: 5,
            cert: fs.readFileSync(CERT_FILE),
            key: fs.readFileSync(KEY_FILE),
            reconnectPeriod: 0,
            enableTrace: false
        }
        //connect
        const client = mqtt.connect(options);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;MQTT Event Handlers implementation:&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;client.on('connect', (packet) =&amp;gt; {
            console.log('connected');
            console.log('subscribing to', SUB_TOPIC);
            client.subscribe(SUB_TOPIC);
        });
&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;//handle Messages
        client.on('message', (topic, message, properties) =&amp;gt; {
            console.log('Received Message',message.toString());
            console.log('Received Message Properties', properties );

            if(message &amp;amp;&amp;amp; message.toString() === 'DOOR_LOCK' ) {
                console.log('Executing', JSON.stringify(message));
                setTimeout(() =&amp;gt; {
                    const response = 'DOOR_LOCK_SUCCESS';
                    const responseTopic = properties.properties.responseTopic;
                    console.log("ResponseTopic: ", responseTopic);
                    console.log('Publishing Response: ', response," to Topic: ", responseTopic.toString());
                    const cDataString = properties.properties.correlationData.toString();
                    console.log('Correlation Data String: ', cDataString)
                    let correlationDataJSON = JSON.parse(cDataString);
                    correlationDataJSON.resp_ts = new Date().toISOString();
                    correlationDataJSON.cmd = message.toString();

                    client.publish(responseTopic.toString(), response, {
                        qos: 1,
                        properties: {
                            contentType: 'text/plain',
                            correlationData: JSON.stringify(correlationDataJSON)
                        }
                    }, (error, packet) =&amp;gt; {
                          //ERROR Handlers here.
                    });
                }, 5000);
            }
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  App Client Simulator
&lt;/h4&gt;

&lt;p&gt;Connection settings are the same as above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MQTT Event Handlers implementation:&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;//handle the message
        client.on('message', (topic, message,  properties) =&amp;gt; {
        //Only log for now.
            console.log('Received message: ', message.toString());
            console.log('Received message properties: ', properties );   
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Publish the command on Interval for testing purposes:&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;//publish
        setInterval(() =&amp;gt; {
            const requestId = v4();
            // const message = JSON.stringify({ping: 'pong'});
            console.log('Publishing message ');
            client.publish(PUB_TOPIC, 'DOOR_LOCK', {
                    qos: 1, properties: {
                        responseTopic: SUB_TOPIC,
                        contentType: 'text/plain',
                        correlationData: JSON.stringify({
                            requestId: requestId,
                            userId: userId,
                            req_ts: new Date().toISOString()
                        })
                    }
                }
                , (error, packet) =&amp;gt; {
                    console.log(JSON.stringify(packet))
                })
        }, 10000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 2: AWS IoT Rule with Amazon DynamoDB Action
&lt;/h3&gt;

&lt;p&gt;An AWS IoT Rule can be used to enrich the message payload with MQTT 5 response topic information, as well as correlation data and content type. We are interested in both command requests and responses, each of them published to different MQTT topics. Therefore, the IoT Rule we create must select data from both topics, as show in the diagram below. &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%2Fhcy2ak292vbqrvx5x9sb.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%2Fhcy2ak292vbqrvx5x9sb.png" alt="Iot Rule for MQTT 5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because we are building a &lt;em&gt;Vehicle Command Log Store&lt;/em&gt; and in this scenario such payloads are sent with content-type &lt;code&gt;text/plain&lt;/code&gt;, we are filtering only for such messages in the Rule SQL statement. &lt;/p&gt;

&lt;p&gt;As the desired behavior is storing the command messages and metadata in a Dynamo DB table, the rule will prepare a new JSON object to be stored. Each key will be stored as a separate column in Amazon Dynamo DB. A new unique message identifier (&lt;code&gt;msgId&lt;/code&gt;) is created to be the primary key of the table. For extracting the MQTT 5 metadata, the Rule SQL uses the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-sql-functions.html" rel="noopener noreferrer"&gt;&lt;code&gt;get_mqtt_property(name)&lt;/code&gt;&lt;/a&gt; SQL function. Encoding/Decoding functions are used to manipulate data from and to &lt;code&gt;base64&lt;/code&gt; encoded strings. &lt;/p&gt;

&lt;p&gt;The Rule Action to be specified is Amazon DynamoDB, pointing to the previously created table. &lt;/p&gt;

&lt;p&gt;The IoT Rule SQL is shown below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT 
{"msgId": newuuid(), 
"name": decode(encode(*, 'base64'), 'base64'), 
"requestId": decode(get_mqtt_property('correlation_data'), 'base64').requestId, "req_ts": decode(get_mqtt_property('correlation_data'), 'base64').req_ts, 
"cmd": decode(get_mqtt_property('correlation_data'), 'base64').cmd, 
"resp_ts": decode(get_mqtt_property('correlation_data'), 'base64').resp_ts, 
"userId": decode(get_mqtt_property('correlation_data'), 'base64').userId, "responseTopic": get_mqtt_property('response_topic') } 
FROM 'cmd/#' 
where get_mqtt_property('content_type') = 'text/plain'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;After running the simulation for some minutes, you should see your Amazon Dynamo DB table populated with data entries as showed in the image below:&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%2Faefzom8neaq4ch4il4f6.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%2Faefzom8neaq4ch4il4f6.png" alt="DynamoDB Entries"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This blog post shows how to use the MQTT 5 IoT Rules SQL functions to extract MQTT 5 metadata from messages and use them to enrich device payloads. One of the design goals was to achieve enrichment and storage with native cloud integrations and no bespoke message processing code.&lt;/p&gt;

&lt;p&gt;The demonstrated Vehicle Command Log Store use-case is just an example, to explore the art of the possible. For more information about the AWS IoT Core Rules Engine SQL functions for MQTT 5 support, have a look at the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-sql-functions.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If you are interested in detailed walk-through a live demo of this solution, you can watch the &lt;a href="https://youtu.be/acUzYWCYK0M" rel="noopener noreferrer"&gt;YouTube video&lt;/a&gt;. To get notified about more IoT content, you can subscribe to the &lt;a href="https://www.youtube.com/@iotbuilders" rel="noopener noreferrer"&gt;IoT Builders YouTube channel&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Author&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;


&lt;div class="ltag__user ltag__user__id__934452"&gt;
    &lt;a href="/fay_ette" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F934452%2Fc6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg" alt="fay_ette image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/fay_ette"&gt;Alina Dima&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/fay_ette"&gt;An engineer for about 20 years, love solving real world problems with code. I simplify complex problems to help developer communities build better and faster with AWS IoT. &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>mqtt5</category>
      <category>iot</category>
      <category>awsiot</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Coding IoT with Amazon CodeWhisperer AI Coding Companion</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Fri, 12 May 2023 13:51:19 +0000</pubDate>
      <link>https://dev.to/iotbuilders/coding-iot-with-amazon-codewhisperer-ai-coding-companion-4abf</link>
      <guid>https://dev.to/iotbuilders/coding-iot-with-amazon-codewhisperer-ai-coding-companion-4abf</guid>
      <description>&lt;p&gt;Amazon CodeWhisperer AI Coding Companion has been &lt;a href="https://aws.amazon.com/about-aws/whats-new/2023/04/amazon-codewhisperer-generally-available/" rel="noopener noreferrer"&gt;generally available&lt;/a&gt; since April 13th, 2023. Naturally, curiosity got the best of me, so I decided to see if I could rapidly build an IoT application, and have the AI do most of the coding.&lt;/p&gt;

&lt;p&gt;The goal of this experiment was to set up the foundations of a simple IoT application, in about 30 minutes. In terms of tools, I used &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/home.html" rel="noopener noreferrer"&gt;AWS CDK&lt;/a&gt; for infrastructure (TypeScript). I had not used CDK before, even if I had years of experience with AWS CloudFormation, SAM, Amplify. For the IoT app itself, I used JavaScript, the &lt;a href="https://github.com/mqttjs" rel="noopener noreferrer"&gt;MQTT.js&lt;/a&gt; library, and the &lt;a href="https://github.com/mqttjs" rel="noopener noreferrer"&gt;AWS SDK v3&lt;/a&gt; for the AWS IoT Control Plane calls. The idea behind mixing JavaScript and TypeScript was to evaluate how well CodeWhisper could assist me in both languages. &lt;/p&gt;

&lt;p&gt;Curious how good a team CodeWhisperer and me were in this experiment? Keep reading, because I will cover some of the great and no so great experiences of working with CodeWhisperer. &lt;/p&gt;

&lt;p&gt;For those interested in the build details, I have recorded the entire experience. It is available in a 2-episode series on the &lt;a href="https://www.youtube.com/@iotbuilders" rel="noopener noreferrer"&gt;IoT Builders YouTube channel&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Part 1 - CDK for IoT&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/C5OkYqcxcAQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Part 1 - Building the IoT App&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/S9zaFJwzCBs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The code is also available on GitHub: &lt;a href="http://bit.ly/cdk-iot-sample" rel="noopener noreferrer"&gt;http://bit.ly/cdk-iot-sample&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What did I build?
&lt;/h2&gt;

&lt;p&gt;The IoT application is shown in the diagram below. We have an AWS IoT Thing, connected to AWS IoT Core, subscribed to an MQTT topic, and publishing data on another MQTT topic. An AWS IoT Rule picks up the data and invokes a Lambda action which prints out the MQTT message. &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%2Fcyly0nro48km3toa4kd8.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%2Fcyly0nro48km3toa4kd8.png" alt="IoT App Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This application was built in 2 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The AWS Resources were created using CDK: an IoT Thing policy based on &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/example-iot-policies.html" rel="noopener noreferrer"&gt;least privilege&lt;/a&gt; best practices, an IoT Rule, a Lambda action and of course the Resource policy allowing Lambda invocation from the IoT Rule. &lt;/li&gt;
&lt;li&gt;The IoT application code was written to: create an IoT Thing, create the identity, attach the IoT policy to the certificate, and the certificate to the Thing, create and configure the MQTT client, connect the client to IoT Core, subscribe and publish data. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Amazon CodeWhisperer helped in both steps listed above. It was used to speed up development, by making whole-line and full-function code completions, automatically generating functions and code from natural language comments, and accelerating work with third party libraries like MQTT.js. &lt;/p&gt;
&lt;h2&gt;
  
  
  Getting started with Amazon CodeWhisperer
&lt;/h2&gt;

&lt;p&gt;As a user of &lt;a href="https://www.jetbrains.com/idea" rel="noopener noreferrer"&gt;intellij IDEA&lt;/a&gt;, I have integrated CodeWhisperer into my IDE in 3 easy steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1&lt;/strong&gt;: Installed the latest_ AWS Toolkit plugin_ in IDEA. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2&lt;/strong&gt;: In the IDE, open the AWS extension panel and click the &lt;em&gt;“Start”&lt;/em&gt; button under &lt;em&gt;Developer Tools → CodeWhisperer&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3&lt;/strong&gt;: In the resulting pop-up, select the “Sign in with Builder ID” option. Use your personal email address to sign up and sign in with &lt;a href="https://docs.aws.amazon.com/signin/latest/userguide/sign-in-aws_builder_id.html" rel="noopener noreferrer"&gt;AWS Builder ID&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&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%2Ftdsoh4nvs7pipzfvcg05.gif" 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%2Ftdsoh4nvs7pipzfvcg05.gif" alt="CodeWhisperer SetUp"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What was the Developer Experience like with CodeWhisperer for IoT?
&lt;/h2&gt;

&lt;p&gt;First off, as we saw above, CodeWhisperer is super easy to set up and start. &lt;/p&gt;
&lt;h3&gt;
  
  
  Generating Code from Comments
&lt;/h3&gt;

&lt;p&gt;CodeWhisperer was efficient at generating code from comments. Some interesting examples were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When prompted with the comment: 
&lt;code&gt;// Create AWS Lambda function, with inline code.&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the &lt;strong&gt;result&lt;/strong&gt; was:&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%2F0al1e199x5yjrct0dz2n.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%2F0al1e199x5yjrct0dz2n.png" alt="AI Lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Here is another example of CodeWhisperer coming up with the code to create an IoT thing when prompted by comment:&lt;/li&gt;
&lt;/ul&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%2Fujc6wedrjo94q9gl9t18.gif" 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%2Fujc6wedrjo94q9gl9t18.gif" alt="AI create IoT Thing"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Auto-Completion
&lt;/h3&gt;

&lt;p&gt;CodeWhisperer is a clever tool for auto-completion.  Below is an example of how I fixed the initially incorrect IoT policy using the auto-completion assistance of CodeWhisperer:&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%2F3ym27hbd01i35y12xlpo.gif" 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%2F3ym27hbd01i35y12xlpo.gif" alt="AI IoT policy fix"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  A &lt;em&gt;Problematic&lt;/em&gt; IoT Policy
&lt;/h3&gt;

&lt;p&gt;While trying to get assistance from CodeWhisperer, I struggled with the creation of an IoT policy, using the CDK SDK for Typescript. It took a few attempts at changing my comment prompts to get to an overly permissive and incorrect IoT policy (see below).&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%2Fai57w97qll58syrstjcb.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%2Fai57w97qll58syrstjcb.png" alt="Incorrect IoT Policy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;comment&lt;/em&gt; I provided was:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;// Create IoT policy for IoT Core. Restrict to account id and region. Allow connect with thing name, subscribe to topic and publish on topic.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Coming up with a correct policy, available &lt;a href="https://github.com/aws-iot-builder-tools/cdk-iot-sample/blob/main/lib/cdk_io_t-stack.ts" rel="noopener noreferrer"&gt;here&lt;/a&gt;, was eventually more effort than expected, although, as shown in the video above, CodeWhisperer did a very good job with auto-completion. &lt;/p&gt;
&lt;h3&gt;
  
  
  Coaxing CodeWhisperer into Creating Correct Code
&lt;/h3&gt;

&lt;p&gt;Sometimes, CodeWhisperer generates code that looks just about right, but actually it is not. In fact, sometimes I got tricked into skipping the correct suggestion and went for the incorrect one. &lt;/p&gt;

&lt;p&gt;So, as a developer, you need to take care to pick the correct suggestions. Below is an example: &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%2F3096agsrm902hk4y3az3.gif" 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%2F3096agsrm902hk4y3az3.gif" alt="Incorrect SDK calls AI"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How to make the most of CodeWhisperer?
&lt;/h2&gt;

&lt;p&gt;If you want to make the most of working with CodeWhisperer, the following helps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In general, the more code you already have, the better CodeWhisperer will do.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do your main imports first&lt;/strong&gt; - if you want to use the Control Plane calls for IoT Core, like in my example, import the ClientIoT as a first thing. Afterwards, you CodeWhisperer will anticipate better what you are prompting it to do in your comments. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be very explicit in your comments&lt;/strong&gt; - if you want a JavaScript Lambda function, write that in your comments. Be explicit with the type of resources, the nature of code (if you want a function, say so). The more detailed and explicit your comments are, the better success you will have. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pay attention&lt;/strong&gt; - sometimes CodeWhisperer provides multiple suggestions, and if you do not pay a lot of attention, you get tricked into choosing the incorrect one (as in the example above). Scroll fast between the proposals, and choose the correct one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know when to give up and move on&lt;/strong&gt; - if full code generation from comments does not work out-of-the-box (like in my example with the IoT policy), count your loses on this one, and use the AWS documentation to start it off correctly, and then use CodeWhisperer for auto-completion, once you are on the right track. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Conclusion and Useful Links
&lt;/h2&gt;

&lt;p&gt;To sum up, the experiment of building an IoT application with the assistance of CodeWhisperer was a success. I aimed for 30 minutes, but in reality it probably took about 40, excluding explanations, introduction and conclusions parts of the video, or written this blog. &lt;/p&gt;

&lt;p&gt;If you want to watch the entire experience, it is available in 2 episodes on YouTube: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/C5OkYqcxcAQ" rel="noopener noreferrer"&gt;Part 1-CDK&lt;/a&gt;, &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://youtu.be/S9zaFJwzCBs" rel="noopener noreferrer"&gt;Part 2 - IoT App&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code for the IoT application is available on GitHub: &lt;a href="http://bit.ly/cdk-iot-sample" rel="noopener noreferrer"&gt;http://bit.ly/cdk-iot-sample&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Amazon CodeWhisperer is an AI-powered coding assistant that provides real-time recommendations in your IDE based on your existing code and comments. The tool is available for and can integrate well with various IDEs, including JetBrains. This post talks about my developer experience building an IoT application in about 30 minutes, with the assistance of CodeWhisperer, with some examples of what went well and what did not got well. &lt;/p&gt;

&lt;p&gt;For more information about CodeWhisperer, have a look at the &lt;a href="https://aws.amazon.com/codewhisperer/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. There is also a guide on how to get started with &lt;a href="https://docs.aws.amazon.com/codewhisperer/latest/userguide/language-ide-support.html" rel="noopener noreferrer"&gt;CodeWhisperer and JetBrains&lt;/a&gt; IDEs. &lt;/p&gt;

&lt;p&gt;To watch more such content, subscribe to &lt;a href="https://www.youtube.com/@iotbuilders" rel="noopener noreferrer"&gt;IoT Builders on YouTube&lt;/a&gt; or follow &lt;a href="https://dev.to/iotbuilders"&gt;IoT Builders&lt;/a&gt; on dev.to.&lt;/p&gt;
&lt;h2&gt;
  
  
  Author&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;


&lt;div class="ltag__user ltag__user__id__934452"&gt;
    &lt;a href="/fay_ette" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F934452%2Fc6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg" alt="fay_ette image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/fay_ette"&gt;Alina Dima&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/fay_ette"&gt;An engineer for about 20 years, love solving real world problems with code. I simplify complex problems to help developer communities build better and faster with AWS IoT. &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>iot</category>
      <category>codewhisperer</category>
      <category>cdk</category>
    </item>
    <item>
      <title>Automatically Applying Configuration to IoT Devices with AWS IoT and AWS Step Functions - Part 1</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Thu, 06 Apr 2023 15:59:23 +0000</pubDate>
      <link>https://dev.to/iotbuilders/automatically-applying-configuration-to-iot-devices-with-aws-iot-and-aws-step-functions-part-1-4n13</link>
      <guid>https://dev.to/iotbuilders/automatically-applying-configuration-to-iot-devices-with-aws-iot-and-aws-step-functions-part-1-4n13</guid>
      <description>&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Assumptions&lt;/li&gt;
&lt;li&gt;Tools and Services&lt;/li&gt;
&lt;li&gt;What workflow are we building?&lt;/li&gt;
&lt;li&gt;How it works&lt;/li&gt;
&lt;li&gt;Why this Developer Technique&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Author&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Explicitly defining processes involving IoT devices and externalizing their management and orchestration is a useful mechanism to break down complexity, centralize state management, ensure bounded context and encapsulation in your system design. It is also a useful technique for modelling workflows that must survive external factors which impact IoT device operation in the field, such as intermittent connectivity, reboots or battery loss, causing temporary offline behavior.&lt;/p&gt;

&lt;p&gt;In this blog post series, we will look at a simple example of modeling an IoT device process as a workflow, using primarily &lt;a href="https://aws.amazon.com/iot/" rel="noopener noreferrer"&gt;AWS IoT&lt;/a&gt; and &lt;a href="https://aws.amazon.com/step-functions/" rel="noopener noreferrer"&gt;AWS Step Functions&lt;/a&gt;. Our example is a system where, when a device comes online, you need to get external settings based on the profile of the user the device belongs to and push that configuration to the device. The system that holds the external settings is often a third party system you need to integrate with at API level (HTTPS), based on the API specification and system SLAs. &lt;/p&gt;

&lt;p&gt;A real world example is home automation. A user sets up a default desired temperature for his apartment, based on a User Settings Profile they created when they purchased the gateway responsible for managing the different sensors, including temperature. &lt;/p&gt;

&lt;h2&gt;
  
  
  Assumptions&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;To narrow down this implementation example, here is a list of assumptions: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We refer to the gateway that controls the different sensors as the device. &lt;/li&gt;
&lt;li&gt;The workflow starts every time a device comes online. &lt;/li&gt;
&lt;li&gt;Nothing happens when devices disconnect. The profile is checked only upon reconnects. &lt;/li&gt;
&lt;li&gt;AWS IoT Core interacts only with the gateway, and not with individual sensors. The gateway reports back to confirm the settings have been correctly configured by the respective sensors. &lt;/li&gt;
&lt;li&gt;We will simulate the device behavior using an MQTT client application built with the &lt;a href="https://github.com/mqttjs/MQTT.js" rel="noopener noreferrer"&gt;MQTT.js open-source library&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;Note that: &lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is a sample implementation to get you started. It is not meant to be lifted and shifted for a production environment. It can definitely be used as a starting point. &lt;/li&gt;
&lt;li&gt;The focus point in this solution is on development techniques and not on the type of device or type of configuration that needs to be applied. Therefore, this solution simulates the device device behavior, the config, and the external API. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tools and Services&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;To build the above described scenario, we use the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Step Functions for workflow management and execution. The state machine is available in &lt;a href="https://github.com/aws-iot-builder-tools/iot-config-management-sample/blob/main/statemachine/config_management.asl.json" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. The following AWS Step Function features are used in the sample project:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-task-state.html" rel="noopener noreferrer"&gt;Tasks&lt;/a&gt; - to break down each unit of work.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-choice-state.html" rel="noopener noreferrer"&gt;Choice state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html#use-awssdk-integ" rel="noopener noreferrer"&gt;AWS SDK service integrations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/connect-to-resource.html#connect-wait-token" rel="noopener noreferrer"&gt;Wait for a Callback with the Task Token&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;AWS IoT Core and AWS IoT Rules Engine for the communication with the IoT Device over MQTT and routing of messages from the device and automatically triggering actions based on message content. &lt;/li&gt;

&lt;li&gt;Amazon DynamoDB for storing of Task Tokens needed for the callback service integration pattern of AWS Step Functions. &lt;/li&gt;

&lt;li&gt;AWS Lambda for publishing messages to the device. AWS Lambda is also used for processing responses to temperature set requests from the IoT Device, as well as simulating the Third Party system call to retrieve the user default desired temperature. &lt;/li&gt;

&lt;li&gt;The device simulator is build in JavaScript, using the open-source Node.js MQTT.js client library. &lt;/li&gt;

&lt;li&gt;All the AWS resources are created and deployed using AWS SAM. The AWS SAM template is available in &lt;a href="https://github.com/aws-iot-builder-tools/iot-config-management-sample/blob/main/template.yaml" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;You can have a look at the GitHub repository for the entire solution, here: &lt;a href="https://github.com/aws-iot-builder-tools/iot-config-management-sample" rel="noopener noreferrer"&gt;https://github.com/aws-iot-builder-tools/iot-config-management-sample&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What workflow are we building?&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The flow is as follows: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every time the device comes online, the workflow for retrieving the user profile, to understand their desired room temperature kicks off. The desired temperature is stored in the user profile, available via an API call to an external system. We simulate this system call using an AWS Lambda function. &lt;/li&gt;
&lt;li&gt;The workflow retrieves the external ID connecting the device to the user it belongs to from IoT thing attributes. It then makes the call to the third party system to retrieve the user profile with the desired temperature value, publishes a message with the configuration setting to the MQTT topic the device is subscribed to, and enters a callback Task, which pauses waiting for the event from the device to come back on the configured response MQTT topic. &lt;/li&gt;
&lt;li&gt;Upon receiving and parsing the response, success or failure is determined, the paused Task is terminated on callback with the respective result, and the AWS Step Functions workflow terminates. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Building an automatically triggered workflow contributes to a nice user experience. There is no need for manual intervention to synchronize the IoT device with user specific configuration settings. This is a simple example to introduce the concept. The workflow can get more complex, with more settings and more involved systems. &lt;/p&gt;

&lt;h2&gt;
  
  
  How it works&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Fig. 1 below shows the interactions between the different components. &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%2Fev0sf82h2ga6r1450odz.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%2Fev0sf82h2ga6r1450odz.png" alt="How it Works"&gt;&lt;/a&gt; Fig. 1 - &lt;em&gt;How it works diagram&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The interactions can be described as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The device comes online and an MQTT presence event is published on the AWS topic &lt;code&gt;$aws/events/presence/connected/+&lt;/code&gt;. (&lt;strong&gt;1&lt;/strong&gt; in Fig. 1 ) &lt;/li&gt;
&lt;li&gt;An AWS IoT Rule is configured on the above topic, with the Rule Action being an AWS Step Function State Machine execution trigger. The Rule SQL looks as follows: &lt;code&gt;SELECT *, topic(5) AS thingName FROM $aws/events/presence/connected/+&lt;/code&gt;
(&lt;strong&gt;2&lt;/strong&gt; in Fig. 1 )&lt;/li&gt;
&lt;li&gt;On MQTT connect presence event, the Rule will pick up the event and pass it as input to the state machine, which will be started on Rule execution (&lt;strong&gt;3&lt;/strong&gt; in Fig. 1 ). The workflow steps will execute as follows: 

&lt;ul&gt;
&lt;li&gt;Firstly, the &lt;strong&gt;IoT DescribeThing SDK call&lt;/strong&gt; will be made to retrieve the thing from the Device Registry. The external ID thing attribute will be retrieved and passed on to the next step. Note that the &lt;a href="https://docs.aws.amazon.com/step-functions/latest/dg/supported-services-awssdk.html#use-awssdk-integ" rel="noopener noreferrer"&gt;AWS Step Functions SDK integration&lt;/a&gt; is used at this step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3Party_GetUserProfileForDevice&lt;/strong&gt; is executed as a next step. This is an AWS Lambda function which simulates a call to a third party system. 3Party_GetUserProfileForDevice returns a randomly generated desired temperature value for an external ID and thing name. (&lt;strong&gt;4&lt;/strong&gt; in the Fig. 1 ).&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;SetConfigurationOnDevice&lt;/strong&gt; AWS Lambda function uses the IoTDataPlaneClient to publish a message to the IoT Device on the MQTT request topic with the desired temperature value. (&lt;strong&gt;5&lt;/strong&gt; in Fig. 1 ), and go next into a “Wait for Callback” Task, waiting for confirmation of the configuration setting from the device.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;“Wait for Callback” Task&lt;/strong&gt; integrates an AWS DynamoDB PutItem SDK call. A task token is generated by AWS Step Functions and sent into the Task as input. We store the token so that we can identify and correlate which token corresponds to the request the device sends the response for. The token is stored in an Amazon DynamoDB table, together with the name of the operation (in this case &lt;code&gt;SET_TEMP&lt;/code&gt;), a unique operation ID (passed as input from the Rules Engine MQTT event session ID ), the device ID (thing name) and a status value of &lt;code&gt;ACTIVE&lt;/code&gt;. The DynamoDB table is configuration is shown below:
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  CMTaskTokens:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName:  CMTaskTokens
      AttributeDefinitions:
        - AttributeName: operationId
          AttributeType: S
        - AttributeName: token
          AttributeType: S

      KeySchema:
        - AttributeName: operationId
          KeyType: HASH
        - AttributeName: token
          KeyType: RANGE
      BillingMode: PAY_PER_REQUEST
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;The device receives the request (&lt;strong&gt;6&lt;/strong&gt; in Fig. 1 ), attempts the operation, and sends the event confirming the result on the MQTT response topic (&lt;strong&gt;7&lt;/strong&gt; in Fig. 1 ). An IoT Rule picks up the incoming event, and invokes an AWS Lambda Function (&lt;strong&gt;8&lt;/strong&gt; in Fig. 1 ) which : 

&lt;ul&gt;
&lt;li&gt;Parses the response and establishes success or failure.&lt;/li&gt;
&lt;li&gt;Retrieves the token entry based on the operation ID from the database table and uses it to terminate the AWS Step Function &lt;strong&gt;WaitForConfirmationEventFromDevice&lt;/strong&gt; state with either success or failure.(&lt;strong&gt;9&lt;/strong&gt; in Fig. 1 ).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The result from the evaluation of the MQTT response event from the IoT device is passed further into a Choice Task, which determines state machine termination with with either success or failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to Deploy and Run this in your AWS Account
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Pre-requisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Clone the GitHub repo: &lt;a href="https://github.com/aws-iot-builder-tools/iot-config-management-sample" rel="noopener noreferrer"&gt;iot-config-management-sample&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the root directory, &lt;code&gt;iot-config-management-sample&lt;/code&gt;, run the following commands:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      sam build 
      sam deploy --guided 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Start the device simulator: 

&lt;ul&gt;
&lt;li&gt;Add and validate your configuration in &lt;code&gt;iot-config-management-sample/device/config.js&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const config =
{
    iotEndpoint: '&amp;lt;YOUR IoT Endpoint&amp;gt;',
    clientId: '&amp;lt;YOUR Thing Name&amp;gt;',
    policyName: '&amp;lt;YOUR IoT Policy&amp;gt;',
    verbosity: 'warn',
    region: '&amp;lt;YOUR AWS Region&amp;gt;',
    shouldCreateThingAndIdentity: &amp;lt;true or false&amp;gt; // if true, the simulator will create the AWS IoT Thing and unique identity. Certificate and Key will be stored in certs/
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If your &lt;code&gt;shouldCreateThingAndIdentity&lt;/code&gt; flag is set to &lt;code&gt;false&lt;/code&gt;, you need to make sure the IoT thing, certificate and key have already been created, and store the certificate and key in the certs folder prior to running the MQTT client. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the simulator: &lt;code&gt;node simulator.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If the simulator is successfully started, you should already see that an AWS Step Functions workflow was triggered automatically, once your device successfully connected to AWS IoT. &lt;u&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/u&gt; that the simulator implements a delay of &lt;code&gt;10 seconds&lt;/code&gt; between receiving the request and sending a successful response.&lt;/li&gt;
&lt;li&gt;Verify that the workflow was successfully triggered: 

&lt;ul&gt;
&lt;li&gt;Log into the AWS Console, navigate to AWS Step Functions, find the &lt;code&gt;ConfigManagement&lt;/code&gt; State Machine, and explore the execution, as shown in the 2 images below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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%2Fs9582tr5hotatp3wmbks.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%2Fs9582tr5hotatp3wmbks.png" alt="Waiting for MQTT response from the device"&gt;&lt;/a&gt; Fig. 2 - &lt;em&gt;Waiting for MQTT response from the device&lt;/em&gt;&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%2Fmwz5c08ifb0idru7bgcc.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%2Fmwz5c08ifb0idru7bgcc.png" alt="Successful workflow execution"&gt;&lt;/a&gt;Fig 3- &lt;em&gt;Successful workflow execution&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Why this Developer Technique? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The advantages of modeling the workflow using AWS Step Functions are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The workflow is explicitly defined and exists outside of various system interactions or the IoT device. &lt;/li&gt;
&lt;li&gt;Flexibility in configuring retries, error handling and timeouts, at each step:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DescribeThing&lt;/strong&gt; can run into TPS limits caused by too many concurrent calls to AWS IoT. You can configure your state machine to retry this step, with an exponential back-off strategy. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calls to the Third Party systems&lt;/strong&gt; can fail with various errors, some of which are worth retrying on. Exception Handling and Retries can be configured at Task level.&lt;/li&gt;
&lt;li&gt;If the &lt;strong&gt;device goes offline temporarily&lt;/strong&gt; during the workflow execution for whatever reason, you can configure a reasonable &lt;a href="https://docs.aws.amazon.com/step-functions/latest/apireference/API_SendTaskHeartbeat.html" rel="noopener noreferrer"&gt;Heartbeat&lt;/a&gt; on the Callback Task. The workflow then pauses until either a message from the device arrives or the timeout is reached. In this way, workflows can exist in the cloud outside of whatever is going on with the device, for as long as needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AWS Step Functions &lt;strong&gt;centralizes state management&lt;/strong&gt; for each step in the workflow, as well as the workflow as a whole. Tracing, logging and metrics  are available as execution level, and at task level. These observability features, as well as the integration with AWS X-Ray and Amazon CloudWatch will be covered in Part 2 of this blog series. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Conclusion&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In the first part of this blog series, we looked at modelling and building the process of automatically applying configuration to an IoT device, based on default settings in a user profile, using AWS Steps Functions, AWS IoT, Amazon Dynamo DB, AWS Lambda and the open-source MQTT.js client library. This is a developer technique used to reduce complexity in workflows involving IoT devices. To understand more about the implementation, have a look at the code in GitHub. &lt;/p&gt;

&lt;p&gt;For a more complex example of an IoT Workflow, you can have a look at the firmware upgrade (OTA) flow built using AWS IoT and AWS Step Functions in the &lt;a href="https://github.com/aws-iot-builder-tools/iot-workflow-management-and-execution" rel="noopener noreferrer"&gt;iot-workflow-management-and-execution GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are curious to learn more about IoT workflow orchestration, watch our IoT Builders YouTube episodes: &lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/JcTd-hx90PY"&gt;
&lt;/iframe&gt;
&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/3H4I09ZsEws"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;Stay tuned for the next blog of the series, where we explore in detail observability aspects such as logging, tracing and metrics for this workflow. &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/fay_ette" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/alinadima/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;. &lt;/p&gt;
&lt;h2&gt;
  
  
  Author&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;


&lt;div class="ltag__user ltag__user__id__934452"&gt;
    &lt;a href="/fay_ette" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F934452%2Fc6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg" alt="fay_ette image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/fay_ette"&gt;Alina Dima&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/fay_ette"&gt;An engineer for about 20 years, love solving real world problems with code. I simplify complex problems to help developer communities build better and faster with AWS IoT. &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>awsiot</category>
      <category>awsstepfunctions</category>
      <category>mqttjs</category>
      <category>orchestration</category>
    </item>
    <item>
      <title>Decoding USP protobuf data sent by USP agents, using the recent AWS IoT Rules Engine native SQL decode function</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Tue, 03 Jan 2023 10:41:13 +0000</pubDate>
      <link>https://dev.to/iotbuilders/decoding-usp-protobuf-data-sent-by-usp-agents-using-the-recent-aws-iot-rules-engine-native-sql-decode-function-1ja0</link>
      <guid>https://dev.to/iotbuilders/decoding-usp-protobuf-data-sent-by-usp-agents-using-the-recent-aws-iot-rules-engine-native-sql-decode-function-1ja0</guid>
      <description>&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Context&lt;/li&gt;
&lt;li&gt;Set-Up Steps&lt;/li&gt;
&lt;li&gt;Exploring the payloads and testing with the AWS IoT Console MQTT Client&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Author&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This post is a follow-up to: &lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/iotbuilders" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&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%2Forganization%2Fprofile_image%2F6216%2Fddd49f15-6f30-4dce-a7bc-dcc4b7001e3f.png" alt="IoT Builders"&gt;
      &lt;div class="ltag__link__user__pic"&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%2Fuser%2Fprofile_image%2F934452%2Fc6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/iotbuilders/connect-the-open-broadband-usp-agent-to-aws-iot-core-using-mqtt5-and-validate-the-integration-with-aws-iot-core-device-advisor-2kb5" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Connect the Open Broadband USP Agent to AWS IoT Core using MQTT5, and Validate the Integration with AWS IoT Core Device Advisor&lt;/h2&gt;
      &lt;h3&gt;Alina Dima for IoT Builders ・ Dec 9 '22&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#awsiot&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tr369&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#telco&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#mqtt5&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
, which showed how to connect a device running obuspa to AWS IoT Core, over MQTT 5, ingest data and validate the MQTT 5 connection using AWS IoT Core Device Advisor. It is recommended you read the preceding post, in order to get a better understanding of integrating a USP agent with AWS IoT.  

&lt;p&gt;In this post, you will see how to set up and use the &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/12/aws-iot-core-rules-engine-google-protocol-buffer-messaging-format/" rel="noopener noreferrer"&gt;native AWS IoT Rules Engine protobuf decoding SQL function&lt;/a&gt;, in order to decode USP records and messages sent by &lt;a href="https://usp.technology/specification/02-index-architecture.html#sec:endpoints" rel="noopener noreferrer"&gt;USP agents&lt;/a&gt;, on the fly, without the need for additional AWS Lambda functions with bespoke decoding logic.&lt;/p&gt;
&lt;h2&gt;
  
  
  Context&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/protocol-buffers" rel="noopener noreferrer"&gt;Protocol Buffers (protobuf)&lt;/a&gt; is an open-source data format used to serialize structured data in binary form. It is used for transmitting data over networks or storing it in files. Protobuf allows you to send data in small packet sizes and at a faster rate than other messaging formats. &lt;a href="https://dev.to/iotbuilders/connect-the-open-broadband-usp-agent-to-aws-iot-core-using-mqtt5-and-validate-the-integration-with-aws-iot-core-device-advisor-2kb5#Introduction"&gt;USP&lt;/a&gt; specifies Protocol Buffers Version 3 as a &lt;a href="https://usp.technology/specification/05-index-encoding.html#sec:encoding" rel="noopener noreferrer"&gt;mechanism to serialize data to be sent over a Message Transfer Protocol, such as MQTT&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The protobuf decoding support in the AWS IoT Rules Engine was recently introduced (&lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/12/aws-iot-core-rules-engine-google-protocol-buffer-messaging-format/" rel="noopener noreferrer"&gt;https://aws.amazon.com/about-aws/whats-new/2022/12/aws-iot-core-rules-engine-google-protocol-buffer-messaging-format/&lt;/a&gt;) to enable developers to decode protobuf payloads to JSON format directly in the rule, and route them to downstream services, by means of an AWS IoT Rules SQL function: decode(value, decodingScheme) (&lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-sql-functions.html#iot-sql-decode-base64" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/iot/latest/developerguide/iot-sql-functions.html#iot-sql-decode-base64&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This feature is interesting because it removes the need to write and maintain custom protobuf decoding logic, which was, prior to this feature, usually done using AWS Lambda functions, invoked either as Rule Actions, or as part of IoT Rule SQL expressions (see the diagram below - before and after the native protobuf support in AWS IoT Rules Engine).&lt;/p&gt;

&lt;p&gt;!(&lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ssc6t3oihgvwqpp24ggp.png" rel="noopener noreferrer"&gt;https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ssc6t3oihgvwqpp24ggp.png&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;
  
  
  Set-Up Steps&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prepare the required protobuf files&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As part of the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/binary-payloads.html#binary-payloads-protobuf-prerequisites" rel="noopener noreferrer"&gt;AWS IoT Rule decoding pre-requisites&lt;/a&gt;, the protobuf descriptor file needs to be created and uploaded to an S3 bucket.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the &lt;a href="https://github.com/protocolbuffers/protobuf/releases" rel="noopener noreferrer"&gt;Protobuf Compiler (protoc)&lt;/a&gt; on your system. On MacOS, you could use Homebrew, as described &lt;a href="https://formulae.brew.sh/formula/protobuf" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Download the 2 proto files &lt;a href="https://github.com/BroadbandForum/usp/blob/master/specification/usp-record-1-2.proto" rel="noopener noreferrer"&gt;record&lt;/a&gt; and &lt;a href="https://github.com/BroadbandForum/usp/blob/master/specification/usp-msg-1-2.proto" rel="noopener noreferrer"&gt;message&lt;/a&gt; from the open source USP GitHub repository, corresponding to the USP version that you want to use in your project. This post will work with the latest version, USP 1.2. &lt;/li&gt;
&lt;li&gt;Create the descriptor file required by the AWS IoT Rules Engine, as described in the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/binary-payloads.html#binary-payloads-protobuf" rel="noopener noreferrer"&gt;docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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;protoc —descriptor_set_out=usp-1-2.desc —proto_path=&amp;lt;PATH TO YOUR PROTO FILES&amp;gt; —include_imports usp-record-1-2.proto usp-msg-1-2.proto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Create the AWS Cloud resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You will need to create the AWS IoT Rule, correct Roles and Policies, and S3 Bucket where the descriptor file will be uploded. You can use the AWS CloudFormation template below for this set-up. To create the AWS resources using this template, you can use the &lt;a href="https://docs.aws.amazon.com/cli/latest/reference/cloudformation/index.html" rel="noopener noreferrer"&gt;AWS CloudFormation CLI commands&lt;/a&gt; or the &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-command-reference.html" rel="noopener noreferrer"&gt;AWS SAM CLI commands&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;For the purpose of this example, the Rule will decode the protobuf record, then decode the protobuf message (both using the decode () SQL function), and then republish the resulting JSON object, on a new topic, so we can examine correctness.&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="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2010-09-09'&lt;/span&gt;
&lt;span class="na"&gt;Transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless-2016-10-31&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;USPProtobufDecodingRule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IoT::TopicRule&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;RuleName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;USPProtobufDecodingRule&lt;/span&gt;
      &lt;span class="na"&gt;TopicRulePayload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;AwsIotSqlVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2016-03-23&lt;/span&gt;
        &lt;span class="na"&gt;RuleDisabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;False&lt;/span&gt;
        &lt;span class="na"&gt;Sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SELECT VALUE decode(decode(encode(*, 'base64'), 'proto', 'usp-1-2', 'usp-1-2.desc', 'usp-record-1-2.proto', 'Record').noSessionContext.payload, 'proto', 'usp-1-2', 'usp-1-2.desc', 'usp-msg-1-2.proto', 'Msg') FROM '/usp/controller'&lt;/span&gt;
        &lt;span class="na"&gt;Actions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Republish&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;RoleArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;RepublishDecodedRole.Arn&lt;/span&gt;
              &lt;span class="na"&gt;Topic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/usp/controller/decoded'&lt;/span&gt;

  &lt;span class="na"&gt;RepublishDecodedRole&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::Role&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2012-10-17&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sts:AssumeRole&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iot.amazonaws.com&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;PolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;allowRepublish&lt;/span&gt;
          &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2012-10-17&lt;/span&gt;
            &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
                &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;iot:Publish&lt;/span&gt;
                &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Join&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iot:"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::Region"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS::AccountId"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:topic//usp/controller/decoded"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

  &lt;span class="na"&gt;USPBucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::Bucket&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;BucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;usp-1-2-bucket&lt;/span&gt;

  &lt;span class="na"&gt;USPBucketPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::BucketPolicy&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;USPBucket&lt;/span&gt;
      &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2012-10-17&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3:Get*'&lt;/span&gt;
            &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Join&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;arn:aws:s3:::'&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;USPBucket&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/*&lt;/span&gt;
            &lt;span class="na"&gt;Principal&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iot.amazonaws.com&lt;/span&gt;

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

&lt;/div&gt;


&lt;p&gt;The AWS IoT Rule SQL expression for decoding could look like below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;SELECT VALUE decode&lt;span class="o"&gt;(&lt;/span&gt;decode&lt;span class="o"&gt;(&lt;/span&gt;encode&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;, &lt;span class="s1"&gt;'base64'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="s1"&gt;'proto'&lt;/span&gt;, &lt;span class="s1"&gt;'usp-1-2'&lt;/span&gt;, &lt;span class="s1"&gt;'usp-1-2.desc'&lt;/span&gt;, &lt;span class="s1"&gt;'usp-record-1-2.proto'&lt;/span&gt;, &lt;span class="s1"&gt;'Record'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.noSessionContext.payload, &lt;span class="s1"&gt;'proto'&lt;/span&gt;, &lt;span class="s1"&gt;'usp-1-2'&lt;/span&gt;, &lt;span class="s1"&gt;'usp-1-2.desc'&lt;/span&gt;, &lt;span class="s1"&gt;'usp-msg-1-2.proto'&lt;/span&gt;, &lt;span class="s1"&gt;'Msg'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; FROM &lt;span class="s1"&gt;'/usp/controller'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The SQL rule behaves the following way: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, the binary MQTT payload is transformed in a based64-encoded string, &lt;/li&gt;
&lt;li&gt;Then, the base64 encoded string is protobuf-decoded at USP record level, as specified by the descriptor,&lt;/li&gt;
&lt;li&gt;Finally, the USP message inside the record, located in the payload object, is protobuf decoded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because USP messages are encoded and wrapped inside encoded USP records, you will need to call the decode function twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upload the descriptor file and start obuspa&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload the descriptor file created in step 3 into your S3 bucket. You can do this using the AWS CLI or AWS Console. &lt;/li&gt;
&lt;li&gt;You can now set up and start the obuspa, as described in the following sections: &lt;a href="https://dev.to/iotbuilders/connect-the-open-broadband-usp-agent-to-aws-iot-core-using-mqtt5-and-validate-the-integration-with-aws-iot-core-device-advisor-2kb5#MQTT5config"&gt;Integrate obuspa with AWS IoT Core over MQTT5&lt;/a&gt; and &lt;a href="https://dev.to/iotbuilders/connect-the-open-broadband-usp-agent-to-aws-iot-core-using-mqtt5-and-validate-the-integration-with-aws-iot-core-device-advisor-2kb5#VerifyMQTT5Integration"&gt;Verify MQTT 5 Integration/Protobuf Data Publishing&lt;/a&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once the agent is sending data, the set-up is complete.&lt;/p&gt;
&lt;h2&gt;
  
  
  Exploring the payloads and testing with the AWS IoT Console MQTT Client&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As the protobuf records arrive on the topic, the IoT Rule will pick them up, decode them, and republish the JSON objects on the &lt;code&gt;/usp/controller/decoded&lt;/code&gt; topic. If you subscribe with the test MQTT Client in the AWS IoT Console, you will be able to see the protobuf records on the &lt;code&gt;/usp/controller&lt;/code&gt; topic, and the JSON payloads on the &lt;code&gt;/usp/controller/decoded&lt;/code&gt; topic, as shown in the images below. The first image shows the original protobuf encoded USP record, arriving on the topic, and the second image the decoded USP message, in JSON format.&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%2Fpaeprjy6qubcq6fmzi0b.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%2Fpaeprjy6qubcq6fmzi0b.png" alt="Original protobuf encoded USP record"&gt;&lt;/a&gt;&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%2Fqqeul4e39nass6oibxhr.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%2Fqqeul4e39nass6oibxhr.png" alt="Decoded USP record and message, in JSON format"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This post shows how to to decode protobuf records and messages sent by a USP agent, directly in the AWS IoT Rules Engine, using the decode function, as part of the rule expression. This is an AWS IoT Rules Engine feature released &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/12/aws-iot-core-rules-engine-google-protocol-buffer-messaging-format/" rel="noopener noreferrer"&gt;recently&lt;/a&gt;, making it easier to use protobuf directly in your &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-rules.html" rel="noopener noreferrer"&gt;IoT Rule&lt;/a&gt;, without the need to write and maintain custom decoding code in AWS Lambda functions. &lt;/p&gt;
&lt;h2&gt;
  
  
  Author&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;


&lt;div class="ltag__user ltag__user__id__934452"&gt;
    &lt;a href="/fay_ette" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&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%2Fuser%2Fprofile_image%2F934452%2Fc6e04565-b2d8-4af5-9f35-32989d5e7b88.jpg" alt="fay_ette image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/fay_ette"&gt;Alina Dima&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/fay_ette"&gt;An engineer for about 20 years, love solving real world problems with code. I simplify complex problems to help developer communities build better and faster with AWS IoT. &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>awsiot</category>
      <category>tr369</category>
      <category>protobuf</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Connect the Open Broadband USP Agent to AWS IoT Core using MQTT5, and Validate the Integration with AWS IoT Core Device Advisor</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Fri, 09 Dec 2022 10:13:05 +0000</pubDate>
      <link>https://dev.to/iotbuilders/connect-the-open-broadband-usp-agent-to-aws-iot-core-using-mqtt5-and-validate-the-integration-with-aws-iot-core-device-advisor-2kb5</link>
      <guid>https://dev.to/iotbuilders/connect-the-open-broadband-usp-agent-to-aws-iot-core-using-mqtt5-and-validate-the-integration-with-aws-iot-core-device-advisor-2kb5</guid>
      <description>&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Introduction&lt;/li&gt;
&lt;li&gt;Scope&lt;/li&gt;
&lt;li&gt;Integrate obuspa with AWS IoT Core over MQTT5&lt;/li&gt;
&lt;li&gt;Verify MQTT 5 Integration/Protobuf Data Publishing&lt;/li&gt;
&lt;li&gt;Validate MQTT 5 Integration with AWS IoT Core Device Advisor “Qualification Program Test Suite”&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Introduction &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;&lt;a href="https://usp.technology/" rel="noopener noreferrer"&gt;User Services Platform&lt;/a&gt;&lt;/em&gt; (USP), also called TR-369, is a standardized protocol for &lt;strong&gt;managing&lt;/strong&gt;, &lt;strong&gt;monitoring&lt;/strong&gt;, &lt;strong&gt;upgrading&lt;/strong&gt;, and &lt;strong&gt;controlling&lt;/strong&gt; connected devices. It is widely used for customer premise equipment (CPE), such as modem routers. This protocol  is the next generation follow-up for Broadband Forum’s &lt;a href="https://www.broadband-forum.org/cwmp" rel="noopener noreferrer"&gt;CPE WAN Management Protocol&lt;/a&gt; (CWMP), commonly known as TR-069. &lt;/p&gt;

&lt;p&gt;The Broadband Forum specification defines USP as "consisting of a collection of Endpoints (&lt;strong&gt;Agents&lt;/strong&gt; and &lt;strong&gt;Controllers&lt;/strong&gt;) that allow applications to manipulate Service Elements (Objects and Parameters that model a given service, such as network interfaces, software modules, device firmware, remote elements proxied through another interface, virtual elements, or other managed services)".  &lt;/p&gt;

&lt;p&gt;Generally, Agents run on CPE devices and can communicate with Controllers over a variety of &lt;a href="https://usp.technology/specification/04-index-mtp.html#sec:mtp" rel="noopener noreferrer"&gt;message transport protocols&lt;/a&gt; (MTPs), one of which is MQTT. MQTT allows a secure, 24/7 open communication channel between Agents and Controllers. USP has specified the usage of both MQTT 5 and MQTT 3.1.1 from early specification versions. &lt;/p&gt;

&lt;p&gt;With the recent general availability of &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/11/aws-iot-general-availability-version-5-mqtt-message-broker-mqtt5/" rel="noopener noreferrer"&gt;MQTT 5 support in AWS IoT Core&lt;/a&gt;, I was eager to test the MQTT 5 integration between the AWS IoT Core MQTT Broker and USP Agents. This post is summarizing my findings.&lt;/p&gt;

&lt;p&gt;For testing purposes, I will be using the Open Source, GitHub available, &lt;a href="https://github.com/BroadbandForum/obuspa" rel="noopener noreferrer"&gt;Open Broadband User Services Platform Agent&lt;/a&gt; (also referred to as OB-USP-Agent or obuspa), a reference C-based implementation of the USP protocol for Agents. &lt;/p&gt;

&lt;h2&gt;
  
  
  Scope &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this post, we will cover the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Configuring the OB-USP-Agent to connect to AWS IoT using MQTT 5.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verifying successful connection to AWS IoT Core over MQTT 5, as well as subscriptions and data publishing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating and running an AWS IoT Core Device Advisor &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/device-advisor-tests.html" rel="noopener noreferrer"&gt;“Qualification Program Test Suite”&lt;/a&gt;, to validate the MQTT 5 client/broker communication. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For those not familiar with &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/device-advisor.html" rel="noopener noreferrer"&gt;AWS IoT Device Advisor&lt;/a&gt;, it is a Cloud-based, fully managed test capability for validating IoT devices during device software development. Device Advisor provides pre-built tests that you can use to validate IoT devices for reliable and secure connectivity with AWS IoT Core, before deploying devices to production. Device Advisor’s pre-built tests help you validate your device software against best practices for usage of &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/protocols.html" rel="noopener noreferrer"&gt;TLS&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/protocols.html" rel="noopener noreferrer"&gt;MQTT&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-device-shadows.html" rel="noopener noreferrer"&gt;Device Shadow&lt;/a&gt;, and &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/iot-jobs.html" rel="noopener noreferrer"&gt;IoT Jobs&lt;/a&gt;. With the recent support for MQTT 5 in AWS IoT Core, MQTT 5 test suites have also been added to Device Advisor.   &lt;/p&gt;

&lt;p&gt;This blog post is a demonstration that &lt;strong&gt;obuspa&lt;/strong&gt; can be configured to integrated with AWS IoT Core over MQTT 5. It is not a solution to be lifted and shifted for production use. The content also assumes some familiarity with USP, especially overall architecture, getting/setting parameters, and configuring USP subscriptions. If you are not already familiar with USP, these concepts are very well explained in the &lt;a href="https://usp.technology/specification/index.html" rel="noopener noreferrer"&gt;USP technical specification&lt;/a&gt;, provided by the Broadband Forum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate obuspa with AWS IoT Core over MQTT5 &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Our first goal is to get obuspa to connect successfully to AWS IoT Core, and perform the pub/sub over MQTT 5. &lt;/p&gt;

&lt;p&gt;Before getting started, make sure you have the following list of per-requisites in place:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download and install Docker. It is very convenient to run obuspa in Docker.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure you have an AWS account, and select a region where the AWS IoT Device Advisor is available, for example: &lt;code&gt;eu-west-1&lt;/code&gt; (Ireland).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enable AWS IoT Logs, for example via the AWS IoT Console.  You can find instructions &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/configure-logging.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To this purpose, it is worth pointing out that support for MQTT 5 client-side is already implemented as part of obuspa. For more details, have a look at the &lt;a href="https://github.com/BroadbandForum/obuspa/blob/master/src/core/mqtt.c" rel="noopener noreferrer"&gt;&lt;code&gt;mqtt.c&lt;/code&gt;&lt;/a&gt; file in obuspa. With this in mind, getting obuspa running and connecting to AWS IoT Core using MQTT 5 should be a matter of configuration, not code. &lt;/p&gt;

&lt;p&gt;To create and test this configuration, we will be using the &lt;a href="https://github.com/BroadbandForum/obuspa/tree/master/tests/mqtt" rel="noopener noreferrer"&gt;test/mqtt&lt;/a&gt; folder, the existing &lt;a href="https://github.com/BroadbandForum/obuspa/blob/master/tests/mqtt/shared.sh" rel="noopener noreferrer"&gt;shared.sh&lt;/a&gt; script (with some minor changes required, which we will discuss later). We will create another test script, inspired by &lt;a href="https://github.com/BroadbandForum/obuspa/tree/master/tests/mqtt" rel="noopener noreferrer"&gt;the existing MQTT test scripts&lt;/a&gt;. We can call it &lt;code&gt;test-mqtt-aws.sh&lt;/code&gt;, and it can look as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;CURRENT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$CURRENT_DIR&lt;/span&gt;
&lt;span class="nv"&gt;CERTS_ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-t tests/mqtt/certs-iot.pem -a tests/mqtt/client-iot.pem"&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CURRENT_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/shared.sh &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1

&lt;span class="c"&gt;#CERTS_ARGS="-t /etc/ssl/certs"&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GREP_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup EXIT
&lt;span class="nb"&gt;trap &lt;/span&gt;cleanup SIGINT

stop_obuspa
&lt;span class="nb"&gt;sleep &lt;/span&gt;1
start_obuspa &lt;span class="nv"&gt;$CERTS_ARGS&lt;/span&gt;

techo
techo &lt;span class="s2"&gt;"Preparing USP Agent for AWS IoT MQTT V5.0."&lt;/span&gt;

add_client 1
verify_client 1

add_local_agent_mtp 1 &lt;span class="o"&gt;||&lt;/span&gt; fail
add_local_agent_controller 1  &lt;span class="o"&gt;||&lt;/span&gt; fail
add_local_agent_controller_mtp 1 &lt;span class="o"&gt;||&lt;/span&gt; fail

set_parameter_client &lt;span class="s2"&gt;"ClientID"&lt;/span&gt; &lt;span class="s2"&gt;"uspTestAgent"&lt;/span&gt;
set_parameter_client &lt;span class="s2"&gt;"ProtocolVersion"&lt;/span&gt; &lt;span class="s2"&gt;"5.0"&lt;/span&gt;

configure_client &lt;span class="s2"&gt;"1"&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;YOUR_AWS_IOT_CORE_ENDPOINT&amp;gt;"&lt;/span&gt; &lt;span class="s2"&gt;"8883"&lt;/span&gt;

obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Device.MQTT.Client.1.TransportProtocol"&lt;/span&gt; &lt;span class="s2"&gt;"TLS"&lt;/span&gt;

&lt;span class="c"&gt;# Enable boot notify (Controller 1)&lt;/span&gt;

obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; add Device.LocalAgent.Subscription
obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; add Device.LocalAgent.Subscription.1

obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Device.LocalAgent.Subscription.1.NotifType"&lt;/span&gt; &lt;span class="s2"&gt;"ValueChange"&lt;/span&gt;
obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Device.LocalAgent.Subscription.1.ReferenceList"&lt;/span&gt; &lt;span class="s2"&gt;"Device."&lt;/span&gt;
obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Device.LocalAgent.Subscription.1.Enable"&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt;
obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Device.LocalAgent.Subscription.1.Recipient"&lt;/span&gt; &lt;span class="s2"&gt;"true"&lt;/span&gt;


&lt;span class="c"&gt;# Finally, enable client.&lt;/span&gt;
enable_client 1

&lt;span class="nb"&gt;sleep &lt;/span&gt;2
&lt;span class="c"&gt;# Log and wipe grep file&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GREP_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$LOG_FILE&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$GREP_FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

techo &lt;span class="s2"&gt;"USP Agent Ready"&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before you can run this script, the following extra steps are needed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Replace the placeholder &lt;code&gt;YOUR_AWS_IOT_CORE_ENDPOINT&lt;/code&gt; with the endpoint from your AWS account. You can read about the IoT endpoint &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/connect-to-iot.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the following AWS IoT Resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS IoT Device Policy (allowing     &lt;code&gt;iot:Connect&lt;/code&gt;,&lt;code&gt;iot:Subscribe&lt;/code&gt;, &lt;code&gt;iot:Publish&lt;/code&gt;, &lt;code&gt;iot:Receive&lt;/code&gt; on     the correct topics),&lt;/li&gt;
&lt;li&gt;Your AWS IoT Thing, with thingName: &lt;strong&gt;uspTestAgent&lt;/strong&gt;, a   new certificate, and attach the newly created IoT Policy,  either via the AWS Console, CLI, or SDK.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You then need to save the device certificate, private key, as well as the root CA, in 2 separate files, which you will reference when starting the obuspa agent. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: &lt;code&gt;certs-iot.pem&lt;/code&gt; must contain the root CA, and &lt;code&gt;client-iot.pem&lt;/code&gt; the private key, followed by unique certificate, like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-----BEGIN&lt;/span&gt; RSA PRIVATE KEY-----
&amp;lt;body&amp;gt;
&lt;span class="nt"&gt;-----END&lt;/span&gt; RSA PRIVATE KEY-----
&lt;span class="nt"&gt;-----BEGIN&lt;/span&gt; CERTIFICATE-----
&amp;lt;body&amp;gt;
&lt;span class="nt"&gt;-----END&lt;/span&gt; CERTIFICATE-----
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;a href="https://github.com/BroadbandForum/obuspa/blob/master/tests/mqtt/shared.sh" rel="noopener noreferrer"&gt;&lt;code&gt;shared.sh&lt;/code&gt;&lt;/a&gt; script, in the &lt;code&gt;add_local_agent_mtp()&lt;/code&gt;, the &lt;code&gt;ResponseTopicConfigured&lt;/code&gt; parameter is configured to &lt;code&gt;'/usp/endpoint/#’&lt;/code&gt;. According to the &lt;a href="https://usp-data-models.broadband-forum.org/tr-181-2-15-1-usp.html" rel="noopener noreferrer"&gt;TR-181 Data Model specification&lt;/a&gt;,  the value MUST NOT contain any wild card characters (“+”, “#”). So, you need to modify the Set cli call, and remove the # in the topic (Not doing this will force an MQTT client disconnect):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Device.LocalAgent.MTP.&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;.MQTT.ResponseTopicConfigured"&lt;/span&gt; &lt;span class="s2"&gt;"/usp/endpoint"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Additionally, set the &lt;code&gt;QoS 1&lt;/code&gt; on publish:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; obuspa_cmd &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="s2"&gt;"Device.LocalAgent.MTP.&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;.MQTT.PublishQoS"&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As a last step, to be able to start up the test script as you run your Docker container, you can replace the existing Docker file, with the following:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;FROM ubuntu:focal

ENV &lt;span class="nv"&gt;MAKE_JOBS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8
ENV &lt;span class="nv"&gt;OBUSPA_ARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-v4"&lt;/span&gt;

&lt;span class="c"&gt;# Add mosquitto latest ppa&lt;/span&gt;
RUN apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; software-properties-common &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    add-apt-repository ppa:mosquitto-dev/mosquitto-ppa

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
RUN apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
    apt-get &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
        libssl-dev &lt;span class="se"&gt;\&lt;/span&gt;
        libcurl4-openssl-dev&lt;span class="se"&gt;\&lt;/span&gt;
        libsqlite3-dev &lt;span class="se"&gt;\&lt;/span&gt;
        libc-ares-dev &lt;span class="se"&gt;\&lt;/span&gt;
        libz-dev &lt;span class="se"&gt;\&lt;/span&gt;
        autoconf &lt;span class="se"&gt;\&lt;/span&gt;
        automake &lt;span class="se"&gt;\&lt;/span&gt;
        libtool &lt;span class="se"&gt;\&lt;/span&gt;
        libmosquitto-dev &lt;span class="se"&gt;\&lt;/span&gt;
        libwebsockets-dev &lt;span class="se"&gt;\&lt;/span&gt;
        pkg-config &lt;span class="se"&gt;\&lt;/span&gt;
        make &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
        apt-get clean

&lt;span class="c"&gt;# Copy in all of the code&lt;/span&gt;
&lt;span class="c"&gt;# Then compile, as root.&lt;/span&gt;
COPY &lt;span class="nb"&gt;.&lt;/span&gt; /obuspa/
RUN &lt;span class="nb"&gt;cd&lt;/span&gt; /obuspa/ &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    autoreconf &lt;span class="nt"&gt;-fi&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    ./configure &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    make &lt;span class="nt"&gt;-j&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAKE_JOBS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    make &lt;span class="nb"&gt;install

&lt;/span&gt;CMD &lt;span class="nb"&gt;cd &lt;/span&gt;obuspa &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;  tests/mqtt/test_mqtt_aws.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build and run your Docker image, and your test will run and start &lt;code&gt;obuspa&lt;/code&gt;, connected to AWS IoT Core, using MQTT 5. &lt;/p&gt;

&lt;h2&gt;
  
  
  Verify MQTT 5 Integration/Protobuf Data Publishing &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Once you have successfully run obuspa in Docker, you should see in the log file of the Agent log statements around the successful transition of the MQTT client state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;SendingConnect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Connect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AwaitingConnect,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;AwaitingConnect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Connect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Callback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Received&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Running&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the AWS IoT Core MQTT Broker side, you can validate that the USP agent is successfully connected, subscribed and publishing data, by looking at the AWS IoT Logs in Amazon CloudWatch, and searching for the following events:&lt;/p&gt;

&lt;p&gt;&lt;u&gt;&lt;em&gt;&lt;em&gt;CONNECT:&lt;/em&gt;&lt;/em&gt;&lt;/u&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"traceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Connect"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MQTT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"clientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uspTestAgent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sourceIp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sourcePort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26259&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt;&lt;em&gt;PUBLISH:&lt;/em&gt;&lt;/u&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"logLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"traceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"accountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Publish-In"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MQTT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"topicName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usp/controller"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"clientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uspTestAgent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"sourceIp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"54.240.197.234"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"sourcePort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26259&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;u&gt;&lt;em&gt;SUBSCRIBE:&lt;/em&gt;&lt;/u&gt;&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"logLevel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INFO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"traceId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"accountId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"eventType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Subscribe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MQTT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"topicName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usp/endpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"clientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uspTestAgent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"principalId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"sourceIp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"sourcePort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;26259&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify that the USP agent has successfully subscribed to the topic configured in your modified &lt;code&gt;shared.sh&lt;/code&gt;(&lt;code&gt;/usp/endpoint&lt;/code&gt;), by looking out for the following log statements in the agent logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Subscribe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sending&lt;/span&gt; &lt;span class="nx"&gt;subscribe&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;usp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;LogCallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MQTT&lt;/span&gt; &lt;span class="nx"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;uspTestAgent&lt;/span&gt; &lt;span class="nx"&gt;sending&lt;/span&gt; &lt;span class="nc"&gt;SUBSCRIBE &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Mid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;usp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;QoS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mh"&gt;0x00&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of the USP subscription to changes in the &lt;code&gt;Device.&lt;/code&gt; data model parameters, you should see MQTT publishing happening from the USP agent, for instantiated data model parameters changing frequently, such as &lt;code&gt;Device.DeviceInfo.UpTime&lt;/code&gt; or &lt;code&gt;Device.Time.CurrentLocalTime&lt;/code&gt; Examples of successful publishing in the agent logs will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;NOTIFY&lt;/span&gt; &lt;span class="nx"&gt;sending&lt;/span&gt; &lt;span class="nx"&gt;at&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="nx"&gt;T11&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="nx"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;host&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;YOUR_AWS_IOT_CORE_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;over&lt;/span&gt; &lt;span class="nx"&gt;MQTT&lt;/span&gt;
&lt;span class="nx"&gt;LogCallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MQTT&lt;/span&gt; &lt;span class="nx"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;uspTestAgent&lt;/span&gt; &lt;span class="nx"&gt;sending&lt;/span&gt; &lt;span class="nc"&gt;PUBLISH &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;q1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;m8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usp/controller&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;164&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;Sending&lt;/span&gt; &lt;span class="nc"&gt;NotifyRequest &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ValueChange&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DeviceInfo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UpTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;....&lt;/span&gt;
&lt;span class="nx"&gt;LogCallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MQTT&lt;/span&gt; &lt;span class="nx"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="nx"&gt;uspTestAgent&lt;/span&gt; &lt;span class="nx"&gt;received&lt;/span&gt; &lt;span class="nc"&gt;PUBACK &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Mid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RC&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;PublishCallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sent&lt;/span&gt; &lt;span class="nx"&gt;MID&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you log into your AWS account, navigate to AWS IoT, select the test MQTT client, and subscribe to the &lt;code&gt;/usp/controller&lt;/code&gt; topic, you should see data coming in. Please note that the data is protobuf-encoded, as specified by the &lt;a href="https://usp.technology/specification/05-index-encoding.html" rel="noopener noreferrer"&gt;USP message encoding specification&lt;/a&gt;.&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%2Fjbqpy85gf8kv5sce5fdb.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%2Fjbqpy85gf8kv5sce5fdb.png" alt="MQTT test client with incoming data"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can, for now, stop the Docker container in which &lt;code&gt;obuspa&lt;/code&gt; is running. This will also ensure the termination of the MQTT connection. &lt;/p&gt;

&lt;h2&gt;
  
  
  Validate MQTT 5 Integration with AWS IoT Core Device Advisor “Qualification Program Test Suite"
&lt;/h2&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After seeing successful MQTT connections, you can use AWS IoT Core Device Advisor, with its “Qualification Program Test Suite”, to validate MQTT 5 functionality and set-up. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; To use AWS IoT Core Device Advisor, you will need to confgure your device with the IoT Endpoint of Device Advisor, which is different than the production IoT Core Endpoint. Hence, this should be done at test phases in your development.&lt;/p&gt;

&lt;p&gt;This step is extremely valuable during device software development, before on-boarding devices to AWS IoT Core. AWS IoT Core Device Advisor also allows you to create your own test suite, not as part of the qualification program, and configure the appropriate tests for your use case. We will however not cover custom suites in this blog post.&lt;/p&gt;

&lt;p&gt;Let’s walk through the steps for setting up AWS IoT Core Device Advisor to run the test suite against the USP agent.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Navigate to the AWS Console, to IoT Core Device Advisor. Use one of the regions where Device Advisor is supported, such as Ireland (&lt;code&gt;eu-west-1&lt;/code&gt;). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;Test Suites&lt;/strong&gt;, create a new &lt;strong&gt;Qualification Test Suite&lt;/strong&gt;:&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%2Fj4c9sdwgoa1746rrv0cl.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%2Fj4c9sdwgoa1746rrv0cl.png" alt="Create new test suite"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose the &lt;strong&gt;“AWS IoT Core qualification test suite”&lt;/strong&gt; for MQTT 5, and click &lt;strong&gt;Next&lt;/strong&gt;:&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%2Fn95471k2wdhi8vf4jzbs.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%2Fn95471k2wdhi8vf4jzbs.png" alt="Create test suite"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On the &lt;strong&gt;Configuration&lt;/strong&gt; page, verify that all the tests in the suite are present (they should be there by default, so no action), and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new &lt;strong&gt;Role&lt;/strong&gt; for AWS IoT Core Device Advisor to perform the needed MQTT actions, and make sure you configure the correct &lt;strong&gt;Action&lt;/strong&gt; permissions, on the correct resources: &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%2Fim8ukjnhgg872qr3vsky.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%2Fim8ukjnhgg872qr3vsky.png" alt="Configure permissions"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Review the test suite, and click &lt;strong&gt;Create Test Suite&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your newly create test suite should appear in the &lt;strong&gt;Test Suites&lt;/strong&gt; section, and you can select it:&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%2Fkfg9ultwtv8cc1607hqy.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%2Fkfg9ultwtv8cc1607hqy.png" alt="Select test suite"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open it, and click &lt;strong&gt;Run test suite&lt;/strong&gt; under &lt;strong&gt;Actions&lt;/strong&gt;:&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%2F7lcm1ofp9zs61cku5w8f.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%2F7lcm1ofp9zs61cku5w8f.png" alt="Run test suite"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select your &lt;strong&gt;IoT thing&lt;/strong&gt;, and copy the &lt;strong&gt;IoT Endpoint&lt;/strong&gt;, as outlined below:&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%2Fmv72runw9t2tq8jkfqrt.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%2Fmv72runw9t2tq8jkfqrt.png" alt="Select IoT thing"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In your &lt;code&gt;obuspa&lt;/code&gt; test script &lt;code&gt;test-mqtt-aws.sh&lt;/code&gt;, replace the IoT endpoint with the Device Advisor endpoint, and rebuild your Docker image. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can now click &lt;strong&gt;Run test&lt;/strong&gt;, and immediately after run your USP Agent Docker container. &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%2Fch0yyepn7rsngh1aoipp.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%2Fch0yyepn7rsngh1aoipp.png" alt="Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will notice that Cloud-side, the test suite is running, and also, that in the &lt;code&gt;obuspa&lt;/code&gt; logs, MQTT tests are being executed. &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%2Fxa84h8kp0fz3b3onims8.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%2Fxa84h8kp0fz3b3onims8.png" alt="Test status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be patient until the &lt;code&gt;obuspa's&lt;/code&gt; MQTT client managed to successfully connect to the IoT endpoint of the Device Advisor, and observe the test suite execution steps, progress, and look at the logs.  &lt;/p&gt;

&lt;p&gt;If all the tests in the suites have passed, the validation has been successful. At the end, you can also download the report with the test results.&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%2Fzomxcdu6sbawm393lq99.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%2Fzomxcdu6sbawm393lq99.png" alt="Results"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;This post shows how the Open Source reference implementation of an USP Agent, &lt;code&gt;obuspa&lt;/code&gt;,  can be configured to &lt;strong&gt;connect&lt;/strong&gt;, &lt;strong&gt;subscribe&lt;/strong&gt; and &lt;strong&gt;publish data&lt;/strong&gt;, over &lt;strong&gt;MQTT 5&lt;/strong&gt;, to AWS IoT Core, following the release of &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/11/aws-iot-general-availability-version-5-mqtt-message-broker-mqtt5/" rel="noopener noreferrer"&gt;MQTT 5 support for IoT Core&lt;/a&gt;. It also shows how to create and configure a “Qualification Program” MQTT 5 test suite, and run it against the agent during development phases. &lt;/p&gt;

&lt;p&gt;For more information around USP, have a look at the &lt;a href="https://usp.technology/specification/index.htm" rel="noopener noreferrer"&gt;specification&lt;/a&gt; released by the Broadband Forum, and the &lt;a href="https://github.com/BroadbandForum/obuspa" rel="noopener noreferrer"&gt;Open Source USP Agent reference implementation&lt;/a&gt;. If you would like to dive deeper into AWS IoT Core Device Advisor, &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/device-advisor.html" rel="noopener noreferrer"&gt;here&lt;/a&gt; is a link to the developer guide. To understand better MQTT 5 support in AWS IoT Core, have a look at the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/mqtt.html" rel="noopener noreferrer"&gt;technical documentation&lt;/a&gt;.&lt;/p&gt;

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

</description>
      <category>awsiot</category>
      <category>tr369</category>
      <category>telco</category>
      <category>mqtt5</category>
    </item>
    <item>
      <title>How to ensure resilience for your AWS IoT Rules Engine to AWS Lambda integration</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Mon, 21 Nov 2022 09:12:30 +0000</pubDate>
      <link>https://dev.to/iotbuilders/how-to-ensure-resilience-for-your-aws-iot-rules-engine-to-aws-lambda-integration-1aoi</link>
      <guid>https://dev.to/iotbuilders/how-to-ensure-resilience-for-your-aws-iot-rules-engine-to-aws-lambda-integration-1aoi</guid>
      <description>&lt;p&gt;If you are using &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/lambda-rule-action.html" rel="noopener noreferrer"&gt;AWS Lambda rule actions&lt;/a&gt; with your AWS IoT Rules, then this post might be of interest to you. I have a question to you: do you know for a fact that all your events are processed successfully, and the function execution is successful for all your events? How do you know that? If these questions make you curious, keep on reading. &lt;/p&gt;

&lt;p&gt;This post will focus on explaining the asynchronous nature of the Lambda invocation from AWS IoT Rules Engine, and the impact it can have on your IoT application, potentially leading to message loss. We will also walk through a working set-up of some resilience steps, using &lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-reference.html" rel="noopener noreferrer"&gt;AWS SAM&lt;/a&gt;, and &lt;a href="https://awslabs.github.io/aws-lambda-powertools-typescript/latest/" rel="noopener noreferrer"&gt;AWS Lambda PowerTools for Typescript&lt;/a&gt;, and &lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html" rel="noopener noreferrer"&gt;AWS X-Ray&lt;/a&gt; for observability. &lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous Lambda invocations
&lt;/h3&gt;

&lt;p&gt;When AWS IoT Rules Engine invokes AWS Lambda, the invocations are asynchronous. This means that AWS Lambda places the event in a queue and AWS IoT Rules records success, regardless of what happens next in your Lambda execution. A separate process reads events from the queue and sends them to your configured function. &lt;/p&gt;

&lt;p&gt;Your AWS Lambda function consists of both your own code and the Lambda runtime itself, and both can be a source of errors that you should handle. So what happens if your function execution leads to an error, be it an error in the function’s code, or a runtime error, such as a timeout? &lt;/p&gt;

&lt;p&gt;Well, in error case, as described &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;, AWS Lambda by default will attempt to run the function with the event 2 times more, with 1 minute wait between the first 2 attempts, and 2 minutes delays before the second and third attempt.&lt;/p&gt;

&lt;p&gt;Additional situations can occur:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your function does not have enough concurrency available to process all incoming events, which can well happen in an IoT application at scale. As a result, additional requests will get throttled (429 HTTP status) by the Lambda service, returned to the event queue, and retried as per &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#async-overview" rel="noopener noreferrer"&gt;Lambda strategy&lt;/a&gt;. The more events in the queue, the higher the retry interval set by Lambda, and the lower the rate at which it reads events from the queue.&lt;/li&gt;
&lt;li&gt;The same event is received multiple times, due to eventual consistency of the event queue.&lt;/li&gt;
&lt;li&gt;The function cannot keep up with the incoming events, and events are deleted from the queue without being sent to the function.&lt;/li&gt;
&lt;li&gt;With events at scale, if the AWS Lambda event queue is very long, new events might expire before AWS Lambda gets to send them to your function. If events expire or processing fails, AWS Lambda discards them. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So clearly this can lead to data loss in your application. &lt;/p&gt;

&lt;h3&gt;
  
  
  Can the &lt;a href="https://docs.aws.amazon.com/iot/latest/developerguide/rule-error-handling.html" rel="noopener noreferrer"&gt;Error Action&lt;/a&gt; help?
&lt;/h3&gt;

&lt;p&gt;The short answer is no, not in this situation.&lt;/p&gt;

&lt;p&gt;The Error Action of the AWS IoT Rules Engine is a great tool for errors that prevent AWS Lambda from accepting the invocation, such as lack of permissions for the rule to trigger your function, or if AWS Lambda is not able to add the event to the queue, but it will not help with errors that happen in your Lambda function’s code, or Lambda runtime (like timeouts). Remember the asynchronous nature of the AWS Lambda function trigger from the IoT Rule. &lt;/p&gt;

&lt;h3&gt;
  
  
  So what can you do?
&lt;/h3&gt;

&lt;p&gt;Luckily, there are a things you can do to ensure that your events do not get lost, and also to try and mitigate the above mentioned situations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure that you have enough concurrency to handle invocations. If you allow the default Lambda retries (2), this also means that these invocations will add to your concurrent invocation count, so keep this in mind.&lt;/li&gt;
&lt;li&gt;Make sure your IoT Cloud application can handle duplicate events as required by your design, and don’t let duplicate events catch you by surprise. For example, ensure that your application code is idempotent, and you design for eventual consistency in your data storage.&lt;/li&gt;
&lt;li&gt;You could reduce the number of retries that the Lambda service performs, or discard unprocessed events quicker. &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-async-errors" rel="noopener noreferrer"&gt;Here&lt;/a&gt; are the docs on how to do this. And if your application code is making calls to other services, you should build a retry strategy, as well as error handling in your application code, inside your Lambda function.&lt;/li&gt;
&lt;li&gt;You can configure &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-async-destinations" rel="noopener noreferrer"&gt;destinations for asynchronous invocation&lt;/a&gt;, for both successful and failed events. Destinations are used by Lambda to send your events to other services, as per configuration. Setting up destinations for failed executions in particular allows you to decouple the handling of your failures without data loss, even if you cannot accommodate Lambda service retries or you figure that your errors are not recoverable with retries. You can configure Amazon SQS, Amazon SNS, Lambda or EventBridge as destinations.
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An alternative to destinations is configuring a &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-dlq" rel="noopener noreferrer"&gt;dead-letter queue&lt;/a&gt;(part of your functions version-specific configuration) in your function’s configuration. Destinations however are more flexible (they are not locked in when you publish a version of your function), support additional targets, and include details about the function's response in the invocation record. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using tracing tools like &lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/aws-xray.html" rel="noopener noreferrer"&gt;AWS X-Ray&lt;/a&gt;, or logging and metrics with Amazon CloudWatch, is great for visibility as to what happens to your AWS Lambda function invocations. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Let’s look at this in an example
&lt;/h3&gt;

&lt;p&gt;The architecture of the example we are building is in the diagram below: &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%2Fzj0u67sl48cpoejnkyoh.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%2Fzj0u67sl48cpoejnkyoh.png" alt="High-Level-Arch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have an AWS IoT Serverless application using AWS SAM, which is composed of an AWS Lambda function invoked from the Rules Engine on every message published by an IoT device on topic &lt;code&gt;'device/&amp;lt;thingName&amp;gt;/from-device'&lt;/code&gt;. For the purpose of our example, the Lambda function will simply throw an error.&lt;/p&gt;

&lt;p&gt;Here is the AWS SAM template for this:&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'
Transform: AWS::Serverless-2016-10-31
Description: &amp;gt;
  rules-engine-to-lambda

  Sample SAM Template for rules-engine-to-lambda

Globals:
  Function:
    Timeout: 60
    Tracing: Active

Resources:
  RulesHandlingFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: app/
      Handler: app.lambdaHandler
      Runtime: nodejs14.x
      Architectures:
        - x86_64
      Tracing: Active
      Environment:
        Variables:
          POWERTOOLS_SERVICE_NAME: RulesToLambdaService
          POWERTOOLS_METRICS_NAMESPACE: rules-engine-to-lambda
          LOG_LEVEL: INFO
      EventInvokeConfig:
        DestinationConfig:
          OnFailure:
            Type: SQS
            Destination: !GetAtt FailedRequestsQueue.Arn
        MaximumEventAgeInSeconds: 120
        MaximumRetryAttempts: 1
      Events:
        IoTLambda:
          Type: IoTRule
          Properties:
            AwsIotSqlVersion: 2016-03-23
            Sql: SELECT * FROM 'device/+/from-device'

    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: "es2020"
        EntryPoints:
        - app.ts

  FailedRequestsQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: "FailedRequestsQueue"
      VisibilityTimeout: 300
      KmsMasterKeyId: alias/aws/sqs

Outputs:
  RulesHandlingFunction:
    Description: "RulesHandlingFunction  ARN"
    Value: !GetAtt   RulesHandlingFunction.Arn
  RulesHandlingFunctionIamRole:
    Description: "Implicit IAM Role for RulesHandlingFunction"
    Value: !GetAtt   RulesHandlingFunction.Arn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the example AWS Lambda function (app.ts), in Typescript. The Typescript function utilizes the Lambda Powertools for Typescript for an easy, descriptor based integration with AWS X-Ray and Amazon CloudWatch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Context } from 'aws-lambda';
import { captureLambdaHandler, Tracer } from '@aws-lambda-powertools/tracer';
import middy from "@middy/core";
import {injectLambdaContext, Logger} from "@aws-lambda-powertools/logger";

const tracer = new Tracer();
const logger = new Logger();

export const lambdaHandler = middy(async (event: any, context: Context): Promise&amp;lt;any&amp;gt; =&amp;gt; {
    logger.info('Event', event)
    throw new Error('This is a test error');
})
    .use(captureLambdaHandler(tracer))
    .use(injectLambdaContext(logger, {clearState: true}));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you publish an event from your IoT device on the topic mentioned above, you can have a look in AWS X-Ray. The service map will look like below. &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%2Fbpi8hwj9ejgllwi4zz91.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%2Fbpi8hwj9ejgllwi4zz91.png" alt="X-Ray service map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the light brown circle around your Lambda function invocation, showing the 4xx Error. However, if you look at the trace, you will see the Response code is 202, as expected for a successful asynchronous invocation. As a reminder here, setting up an Error Action will not help, as from the perspective of your IoT Rule, the AWS Lambda invocation was successful, because AWS Lambda responded with a 202 status code, and there is no reason to invoke the Error Action.&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%2Ft8nkgfssmt9hy14wbh5o.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%2Ft8nkgfssmt9hy14wbh5o.png" alt="Trace"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because we have set &lt;code&gt;MaximumRetryAttempts&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; and the &lt;code&gt;MaximumEventAgeInSeconds&lt;/code&gt; to &lt;code&gt;120 seconds&lt;/code&gt;, if we open the trace we will see that Lambda attempted to invoke the function twice, both times with the same expected failure. If your application is processing large numbers of events, allowing the Lambda service to retry for you, especially with a high value of the &lt;code&gt;MaximumEventAgeInSeconds&lt;/code&gt;, might not be the best strategy, due to the potential loss of newer events. You can also notice the different log entries in Amazon CloudWatch for each invocation, in the image below.&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%2F4ij4n4r90ehkke9zeyhd.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%2F4ij4n4r90ehkke9zeyhd.png" alt="Segments timeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because we have configured an Amazon SQS queue for failure cases, our event is not lost, but was sent to the SQS queue. The destination is configured with &lt;code&gt;DestinationConfig&lt;/code&gt; in the SAM template.  Once the messages land in the SQS queue, you can process them with an idempotent consumer, such as another AWS Lambda function, for example. &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%2F2xiechqni4recfh9hvon.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%2F2xiechqni4recfh9hvon.png" alt="Amazon SQS queue message count"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have a look also at the &lt;a href="https://github.com/aws-iot-builder-tools/aws-iot-rules-engine-to-lambda-sample" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; with all the resources.&lt;/p&gt;

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

&lt;p&gt;This post explains the behaviour of the AWS IoT Rules Engine invoking your AWS Lambda function, the asynchronous nature of the invocation, and the impact it can have on your IoT application, especially if it leads to potential data loss. &lt;/p&gt;

&lt;p&gt;Tools like AWS X-Ray and the Lambda PowerTools help with tracing visibility for your Lambda invocations. Setting up a destination for failed events is a good strategy to ensure data is not getting lost, and you have the possibility for a decoupled handling of failed events, in a parallel path in your application. Programmatic error handling and retries in your Lambda function application code can also work towards your fallback strategy. &lt;/p&gt;

&lt;p&gt;Have a look at the links throughout the blog post, to understand better how asynchronous invocations with AWS Lambda work. &lt;/p&gt;

&lt;p&gt;If you find this interesting or have suggestions for future topics, feel free to reach out here or &lt;a class="mentioned-user" href="https://dev.to/fay_ette"&gt;@fay_ette&lt;/a&gt; on Twitter or &lt;a href="https://www.linkedin.com/in/alina-dima/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>iot</category>
      <category>awslambda</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Some Tips &amp; Tricks when working with AWS IoT Rules Engine</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Tue, 08 Nov 2022 13:46:46 +0000</pubDate>
      <link>https://dev.to/iotbuilders/some-tips-tricks-when-working-with-aws-iot-rules-engine-1c8j</link>
      <guid>https://dev.to/iotbuilders/some-tips-tricks-when-working-with-aws-iot-rules-engine-1c8j</guid>
      <description>&lt;p&gt;The AWS IoT Rules Engine is widely used for routing IoT device messages to different downstream services, based on evaluation of rule statements and conditions. Even if working with the AWS IoT Rules Engine can be straightforward, there are a few tricks to keep in mind when things don’t go according to plan. &lt;/p&gt;

&lt;p&gt;In this post, I will put forward a few tips that you should apply to your AWS IoT Rules-based implementation, to prevent failures, increase observability, and verify that everything works as expected. &lt;/p&gt;

&lt;h2&gt;
  
  
  Enable the AWS IoT Logs
&lt;/h2&gt;

&lt;p&gt;Debugging IoT rule executions is not trivial. Incorrect syntax is usually detected at creation time, however, a lot of issues can only be detected at runtime. When and if something goes wrong, your best bet of identifying the problem is looking in the AWS IoT Logs. Once you enable the AWS IoT Logs, which you can do using the AWS CLI, AWS CloudFormation, CDK or the AWS Console, you should be able to explore the log streams in Amazon CloudWatch Logs, or, at an even more granular level, in CloudWatch Insights. &lt;/p&gt;

&lt;p&gt;With Amazon CloudWatch Insights, for instance, you could examine all the failures in your rule execution with the following query:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fields @timestamp, @message&lt;br&gt;
| filter ruleName="&amp;lt;your-rule-name&amp;gt;" and status = 'Failure'&lt;br&gt;
| sort @timestamp desc&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Don’t forget to configure an Error Action for your Rule
&lt;/h2&gt;

&lt;p&gt;Any of the actions you configure for execution could fail at any point. This can be caused by various reasons, such as missing execution permissions (a very common error, especially in cross account executions), runtime errors, throughput exceeded exceptions appearing at high TPS, just to name a few. &lt;/p&gt;

&lt;p&gt;To ensure resilience, you need to make sure that that you build a mitigation for this point of failure. This mitigation should come in the form of an Error Action, which log your error, ensure you don’t lose data, and allow you to build a decoupled error handling flow. Setting up an error action is easy. &lt;/p&gt;

&lt;p&gt;Below is an AWS CloudFormation S3 Error Action example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActivityToKinesisTopicRule:
  Type: AWS::IoT::TopicRule
  Properties:
    RuleName: "&amp;lt;your-rule-name&amp;gt;"
    TopicRulePayload:
      RuleDisabled: false
      AwsIotSqlVersion: "2016-03-23"
      Sql: "Some SQL"
      Actions:
        - Kinesis:
            RoleArn:&amp;lt;your-kinesis-role&amp;gt;
            StreamName: "your-kinesis-data-stream"
            PartitionKey: "&amp;lt;your key&amp;gt;"
      ErrorAction:
        S3:
          BucketName: "&amp;lt;your-bucket-name&amp;gt;"
          Key: "error-${timestamp()}.json"
          RoleArn: "&amp;lt;your-action-role&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ensure that the SQL Version is set to "Latest" for your IoT Rule
&lt;/h2&gt;

&lt;p&gt;So let me share with you a little anecdote to kick start this best practice section. &lt;/p&gt;

&lt;p&gt;Only just last week, I was building a data ingestion pipeline routing time-series data from IoT devices into Amazon Kinesis Data Streams, via the Rules Engine’s Kinesis Action. As I was doing due diligence and checking if ingestion worked, I noticed that all the array key/value pairs from the device JSON payload were missing from the Kinesis records. No error, no warning, just missing.&lt;/p&gt;

&lt;p&gt;I looked in the IoT logs, checked for Kinesis errors, built an Error Action. But nothing helped. All the executions were cleanly performed, nothing seemed wrong. As I looked closely at my IoT Rule as it was displayed in the AWS IoT console, I noticed that my rule’s SQL version was set to &lt;code&gt;"2015-10-08"&lt;/code&gt;. That was clearly not what I wanted, but, as I forgot to set the desired version in my AWS CloudFormation template, my rule resource got created with the default SQL version, which is the old SQL version &lt;code&gt;"2015-10-08"&lt;/code&gt;. If you create your rule using the AWS SDK, you will see the same behaviour. And, as the old version does not have the right support for arrays, my array key/value pairs in the payload were silently ignored . &lt;/p&gt;

&lt;p&gt;I remembered later that, every once in a while, when I work with the AWS IoT Rules Engine, I found myself encountering one problem or another that ends up being related to using an old SQL version. The behaviour can be unpredictable, so don’t expect a straight forward error message. &lt;/p&gt;

&lt;p&gt;The conclusion here is, as a best practice, make sure you set the SQL version to the desired version explicitly (for example the latest current version &lt;code&gt;"2016-03-23"&lt;/code&gt;) when you create your AWS IoT Rule. &lt;/p&gt;

&lt;h2&gt;
  
  
  Does your IoT Rule have the right permissions?
&lt;/h2&gt;

&lt;p&gt;Failures in your rule execution can be caused by lack of permissions. Your AWS IoT Rule needs an IAM Rule and a policy that allows the AWS IoT service to perform the operations needed to execute the action you specified. If you forget to add this, your rule execution will fail with authorization errors.  Below is an example of an AWS IAM role, that allows your rule to write to an AWS Kinesis Data Stream.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KinesisRuleRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Principal:
            Service:
              - iot.amazonaws.com
          Action:
            - sts:AssumeRole
    Path: "/"
    Policies:
      - PolicyName: AllowKinesis
        PolicyDocument:
          Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - kinesis:PutRecord
              Resource: "&amp;lt;your-kinesis-data-stream-arn"

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

&lt;/div&gt;



&lt;p&gt;In conclusion, working with the AWS IoT Rules Engine can be straightforward, but, when issues occur, debugging is not always trivial. Having a few tricks up your sleeve, like the ones above, can help save some development and debugging time. &lt;br&gt;
The four take-aways from this post are: enabling AWS IoT Logs, adding an Error Action, verifying the SQL version, and giving the AWS IoT Service the needed permissions for your action.  &lt;/p&gt;

&lt;p&gt;If you liked this post and would like to see more, follow me on Twitter (&lt;a href="https://twitter.com/fay_ette"&gt;@fay_yette&lt;/a&gt;), or &lt;a href="https://www.linkedin.com/in/alina-dima/"&gt;LinkedIn&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>iot</category>
    </item>
    <item>
      <title>IoT Builders - Live Stream on Twitter Spaces</title>
      <dc:creator>Alina Dima</dc:creator>
      <pubDate>Mon, 10 Oct 2022 12:02:10 +0000</pubDate>
      <link>https://dev.to/iotbuilders/iot-builders-live-stream-on-twitter-spaces-1nc6</link>
      <guid>https://dev.to/iotbuilders/iot-builders-live-stream-on-twitter-spaces-1nc6</guid>
      <description>&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is IoT Builders&lt;/li&gt;
&lt;li&gt;When?&lt;/li&gt;
&lt;li&gt;How does it work?&lt;/li&gt;
&lt;li&gt;What's coming up this week?&lt;/li&gt;
&lt;li&gt;
What did you miss so far?

&lt;ul&gt;
&lt;li&gt;Episode #1&lt;/li&gt;
&lt;li&gt;Episode #2&lt;/li&gt;
&lt;li&gt;
Episode #3 &lt;/li&gt;
&lt;li&gt;
Episode #4 &lt;/li&gt;
&lt;li&gt;
Episode #5 &lt;/li&gt;
&lt;li&gt;
Episode #6 &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is IoT Builders? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;IoT Builders&lt;/strong&gt; is a live stream hosted by four AWS IoT Developer Advocates - 👩‍💻👨‍💻👨‍💻👨‍💻 (&lt;a href="https://twitter.com/fay_ette"&gt;Alina&lt;/a&gt;, &lt;a href="https://twitter.com/dangross"&gt;Dan&lt;/a&gt;, &lt;a href="https://twitter.com/nenadilic84"&gt;Nenad&lt;/a&gt;, and &lt;a href="https://twitter.com/SyedCloud"&gt;Syed&lt;/a&gt;), aiming to foster engaging conversations with community builders, who tune in weekly to share their experiences building IoT products.&lt;/p&gt;

&lt;h2&gt;
  
  
  When? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Weekly, on &lt;strong&gt;Wednesdays&lt;/strong&gt;, at &lt;strong&gt;5pm CET/ 8am PT&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We invite a new speaker weekly, and we keep the same set or sub-set of hosts. We go into interesting details, ranging from Embedded to Cloud, discuss IoT challenges, walk through educational material etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's coming up this week? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This Wednesday, Oct 26th, we will be talking to Ali Benfattoum, Principal Tech Evangelist for #iot  at #aws. Ali is an expert in #SmartCity #SmartBuilding, #LoRaWAN, and the creator of the #opensource &lt;a href="https://github.com/aws-samples/aws-stf"&gt;Smart Territory Framework&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/i/spaces/1DXxyvPLpmYKM"&gt;Here's&lt;/a&gt; the link to the space 🚀.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did you miss so far? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If you have missed our live streams so far, don't worry! Here is a summary:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Episode #1:&lt;/strong&gt;  &lt;a&gt;&lt;/a&gt; Live September 21st, with Ed Miller from Arm, about Arm Virtual Hardware and other IoT related topics. Below is the list of meaningful topics we covered in the stream.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://avh.arm.com"&gt;ARM Virtual Hardware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://catalog.us-east-1.prod.workshops.aws/workshops/30043722-0362-4859-bc6f-c28836a2d7ac/en-US"&gt;Workshop on Virtual Hardware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devsummit.arm.com"&gt;Arm DevSummit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://studio.keil.arm.com"&gt;Keil Studio in the Cloud&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The recording is available &lt;a href="https://twitter.com/i/spaces/1zqKVPmMPXMJB?s=20"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Episode #2:&lt;/strong&gt; &lt;a&gt;&lt;/a&gt; Live September 28th, with a roundtable discussion with IoT Developer Advocates Nenad Ilic, Alina Dima, Syed Rehan, and Dan Gross. We covered a lot of interesting topics, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How we became Developer Advocates&lt;/li&gt;
&lt;li&gt;What our areas of focus are&lt;/li&gt;
&lt;li&gt;Why we think IoT is cool&lt;/li&gt;
&lt;li&gt;What the biggest challenges of IoT projects for builders are&lt;/li&gt;
&lt;li&gt;What our favourite tools/services are&lt;/li&gt;
&lt;li&gt;Some upcoming events and new services:&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arm.com/company/events/devsummit"&gt;https://arm.com/company/events/devsummit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://reinvent.awsevents.com"&gt;https://reinvent.awsevents.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;New AWS IoT FleetWise going GA (&lt;a href="https://aws.amazon.com/blogs/aws/aws-iot-fleetwise-now-generally-available-easily-collect-vehicle-data-and-send-to-the-cloud/"&gt;Blog&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The recording is available &lt;a href="https://twitter.com/i/spaces/1dRJZMBloevGB?s=20"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Episode #3:&lt;/strong&gt; &lt;a&gt;&lt;/a&gt; Live October 5th, with educator and AWS IoT Hero Stephen Borsay, who joined us to discuss IoT hardware, services, and his new book: &lt;em&gt;"AWS Serverless IoT: Inexpensive IoT Projects to take you from Zero to AWS IoT Hero"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;More details on Steve's great work in the links below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://udemy.com/user/stv/"&gt;Udemy course&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloudboard.cc"&gt;Cloud Board&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amazon.com/dp/B0B9P325F7"&gt;Steve's book&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtube.com/channel/UCiwFO9083gofF-OJMZsYIdg/videos"&gt;Steve's YouTube channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sborsay"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Do check out Steve's &lt;a href="https://cloudboard.cc"&gt;Cloud Board&lt;/a&gt;! You should be in for a hardware treat 🤓.&lt;/p&gt;

&lt;p&gt;The recording is available &lt;a href="https://twitter.com/i/spaces/1RDGlaXEmYVJL?s=20"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Episode #4&lt;/strong&gt; &lt;a&gt;&lt;/a&gt;: Live on October 12th, we had a special session with Head of Developer Relations &lt;a href="https://twitter.com/mender_io"&gt;@mender_io&lt;/a&gt;, &lt;a href="https://twitter.com/TheYoctoJester"&gt;Josef Holzmayr&lt;/a&gt;, who joined us to discuss Embedded Systems, the Yocto Project, as well as importance of OTA.&lt;/p&gt;

&lt;p&gt;The recording is available &lt;a href="https://twitter.com/i/spaces/1vOxwMLqDXLGB?s=20"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Episode #5&lt;/strong&gt; &lt;a&gt;&lt;/a&gt;: Live on October 19th, we had a great session with &lt;a href="https://www.linkedin.com/in/marchcyr/"&gt;Marc H. Cyr&lt;/a&gt; represented the &lt;a href="https://www.linkedin.com/company/iot-network/"&gt;IoT+ Network&lt;/a&gt;, and his 15+ years of IoT with #corporate, #startups, #smallbusiness and #incubators, and the knowledge he acquired building platforms, products and completing projects spanning multiple verticals including: #energy, #utilities, #medical, #iiot, #building, #pharma, #railindustry, #retail, #smartcity, smartstadium, and even consumer iot #smarthome. &lt;/p&gt;

&lt;p&gt;We have discussed at least some of the following topics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;#business / #technology divide.&lt;/li&gt;
&lt;li&gt;Your "competitor" is the best partner you don't have yet.&lt;/li&gt;
&lt;li&gt;Customer's don't care about #iot --&amp;gt; even the best IoT #innovation is invisible.&lt;/li&gt;
&lt;li&gt;#data is a liability, not an asset.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The recording is available &lt;a href="https://twitter.com/i/spaces/1lDGLnDYqmRxm?s=20"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Episode #6&lt;/strong&gt; &lt;a&gt;&lt;/a&gt;: Live on October 26th, we had Ali Benfattoum, Principal Tech Evangelist for #iot  at #aws. Ali is an expert in #SmartCity #SmartBuilding, #LoRaWAN, and the creator of the #opensource &lt;a href="https://github.com/aws-samples/aws-stf"&gt;Smart Territory Framework - STF&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Here are some links to content, if you want to learn more about STF:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;[Blog]&lt;/strong&gt;&lt;a href="https://www.fiware.org/2022/07/04/how-the-smart-territory-framework-helps-territories-create-smart-and-sustainable-services-for-their-residents/"&gt;How the Smart Territory Framework helps territories create smart and sustainable services for their residents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[Youtube]&lt;/strong&gt; &lt;a href="https://youtu.be/4MRZiC1VvKQ"&gt;Smart Territory Framework - Foundations for Smart Territories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[Youtube]&lt;/strong&gt; [Customer reference] &lt;a href="https://www.youtube.com/watch?v=Q_fADZFZqSE"&gt;Heidelberg meets the AWS Smart Territory Framework&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[Youtube]&lt;/strong&gt; [Partner reference] &lt;a href="https://youtu.be/zJ8DKRuQSps"&gt;Smart Territory Framework - Comment SERFIM innove au service des randonneurs et du pastoralisme&lt;/a&gt; (English subtitles available)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[Youtube] [How to]&lt;/strong&gt; &lt;a href="https://youtu.be/iSFtl46h6Vw"&gt;Build a Digital Twin using the Smart Territory Framework and AWS IoT TwinMaker&lt;/a&gt;
[GitHub] &lt;a href="https://github.com/aws-samples/aws-stf"&gt;Smart Territory Framework catalog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[FIWARE Press Release]&lt;/strong&gt; &lt;a href="https://www.fiware.org/news/fiware-foundation-and-aws-join-forces-to-develop-digital-cities/"&gt;FIWARE Foundation and AWS join forces to develop digital cities&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;[NEC Press Release]&lt;/strong&gt; - &lt;a href="https://www.neclab.eu/about-us/press-releases/detail/nec-ngsi-ld-scorpio-broker-selected-for-amazon-web-services-smart-territories-framework"&gt;NEC Scorpio Broker selected for AWS Smart Territories Framework&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The recording is available &lt;a href="https://twitter.com/i/spaces/1DXxyvPLpmYKM"&gt;Here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to participate?
&lt;/h2&gt;

&lt;p&gt;If you are working with IoT, building fun prototypes, or production-ready solutions, embedded or in the Cloud, and want to share your experiences, reach out to us on Twitter, and join as a speaker in our live stream!&lt;/p&gt;

&lt;p&gt;If you want to listen in and learn about IoT, join us Wednesdays, 5pm CET/8am PT! This is a safe space, no matter what your knowledge and experience level with IoT is. &lt;/p&gt;

&lt;p&gt;Follow us on Twitter, for a fresh link to our weekly Twitter spaces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alina Dima: &lt;a href="https://twitter.com/fay_ette"&gt;https://twitter.com/fay_ette&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Dan Gross: &lt;a href="https://twitter.com/dangross"&gt;https://twitter.com/dangross&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Nenad Ilic: &lt;a href="https://twitter.com/nenadilic84"&gt;https://twitter.com/nenadilic84&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Syed Rehan: &lt;a href="https://twitter.com/SyedCloud"&gt;https://twitter.com/SyedCloud&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>iot</category>
      <category>livestream</category>
    </item>
  </channel>
</rss>
