Demonstrate AWS IoT Device Client MQTT message communication using a Raspberry Pi registered with Systems Manager

TOC

Demonstrate AWS IoT Device Client MQTT message communication using a Raspberry Pi registered with Systems Manager

The following page shows how to install the AWS IoT Device Client on a Raspberry Pi.

あわせて読みたい
Install the AWS IoT Device Client on the Raspberry Pi registered in Systems Manager 【Install the AWS IoT Device Client on the Raspberry Pi registered in Systems Manager】 This page describes the AWS IoT Device Client. The AWS IoT Device Cli...

This time, as a continuation, we will experience sending and receiving messages using AWS IoT Device Client, following the official tutorial below.

あわせて読みたい
Tutorial: Demonstrate MQTT message communication with the AWS IoT Device Client - AWS IoT Core Establish MQTT message communication and subcribe to and publish MQTT messages with IoT Device Client.

Environment

Diagram of Demonstrating AWS IoT Device Client MQTT message communication using a Raspberry Pi registered with Systems Manager.

The basic structure is the same as the page introduced at the beginning of this document.

There are two changes.

The first point is the IoT Policy.
This is the policy that applies to the AWS IoT Thing that correspond to the Rasbperry Pi.
Make modifications according to the above tutorial.

The second point is the command to execute in the SSM document.
Run the SSM document against the Raspberry Pi to set up the AWS IoT Device Client installation, etc.
This will also be modified according to the tutorial.

CloudFormation template files

The above configuration is built with CloudFormation.
The CloudFormation template is placed at the following URL

GitHub
awstut-fa/155 at main · awstut-an-r/awstut-fa Contribute to awstut-an-r/awstut-fa development by creating an account on GitHub.

Explanation of key points of template files

As mentioned earlier, the structure of this issue is largely the same as that introduced at the beginning of this report, so we will focus on the changes.

IoT Policy

Resources:
  Policy:
    Type: AWS::IoT::Policy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - iot:Connect
            Resource:
              - !Sub "arn:aws:iot:${AWS::Region}:${AWS::AccountId}:client/${Thing}"
          - Effect: Allow
            Action:
              - iot:Publish
            Resource:
              - !Sub "arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topic/${PublishTopicName}"
          - Effect: Allow
            Action:
              - iot:Subscribe
            Resource:
              - !Sub "arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topicfilter/${SubscribeTopicName}"
          - Effect: Allow
            Action:
              - iot:Receive
            Resource:
              - !Sub "arn:aws:iot:${AWS::Region}:${AWS::AccountId}:topic/${SubscribeTopicName}"
      PolicyName: !Sub "${Prefix}-policy"
Code language: YAML (yaml)

The above settings were made with reference to the following page.

あわせて読みたい
Prepare the Raspberry Pi to demonstrate MQTT message communication - AWS IoT Core Create certificates and provision your Rasperry Pi device for MQTT communication.

In the tutorial we are referring to, the theme is sending/receiving messages.
Therefore, it is necessary to set appropriate permissions on the topics for sending/receiving.

Please see the following page for information on the policy settings required to send and receive messages.

あわせて読みたい
Demonstrate publishing messages with the AWS IoT Device Client - AWS IoT Core Learn how the AWS IoT Device Client can send default and custom MQTT messages.
あわせて読みたい
Demonstrate subscribing to messages with the AWS IoT Device Client - AWS IoT Core Learn how the AWS IoT Device Client can send default and custom MQTT messages.

SSM Document

Resources:
  RunShellScriptAssociation:
    Type: AWS::SSM::Association
    Properties:
      AssociationName: !Sub "${Prefix}-shellscript-association"
      Name: AWS-RunShellScript
      OutputLocation:
        S3Location:
          OutputS3BucketName: !Ref BucketName
          OutputS3KeyPrefix: shellscript-association-log
      Parameters:
        commands:
          - "apt-get -y install build-essential libssl-dev cmake unzip git python3-pip"
          - !Sub 'su - ${UserName} -c "export PATH=$PATH:~/.local/bin"'
          - !Sub 'su - ${UserName} -c "git clone https://github.com/aws/aws-cli.git"'
          - !Sub 'su - ${UserName} -c "cd aws-cli && git checkout v2 && sudo pip3 install --break-system-packages -r requirements.txt"'
          - !Sub 'su - ${UserName} -c "cd aws-cli && git checkout v2 && sudo pip3 install --break-system-packages ."'
        
          - !Sub 'su - ${UserName} -c "mkdir ~/certs"'
          - !Sub 'su - ${UserName} -c "curl -o ~/certs/AmazonRootCA1.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem"'
          - !Sub 'su - ${UserName} -c "chmod 745 ~"'
          - !Sub 'su - ${UserName} -c "chmod 700 ~/certs"'
          - !Sub 'su - ${UserName} -c "chmod 644 ~/certs/AmazonRootCA1.pem"'
          
          - !Sub 'su - ${UserName} -c "git clone https://github.com/awslabs/aws-iot-device-client aws-iot-device-client"'
          - !Sub 'su - ${UserName} -c "mkdir ~/aws-iot-device-client/build"'
          - !Sub 'su - ${UserName} -c "cd ~/aws-iot-device-client/build && cmake ../"'
          - !Sub 'su - ${UserName} -c "cd ~/aws-iot-device-client/build && cmake --build . --target aws-iot-device-client"'
          
          - !Sub 'su - ${UserName} -c "mkdir ~/dc-configs"'
          - !Sub 'su - ${UserName} -c "mkdir ~/messages"'
          - !Sub 'su - ${UserName} -c "mkdir ~/certs/pubsub"'
          - !Sub 'su - ${UserName} -c "mkdir ~/certs/jobs"'
          - !Sub 'su - ${UserName} -c "chmod 745 ~"'
          - !Sub 'su - ${UserName} -c "chmod 700 ~/certs/pubsub"'
          - !Sub 'su - ${UserName} -c "chmod 700 ~/certs/jobs"'
          - !Sub 'su - ${UserName} -c "chmod 745 ~/messages"'

          - !Sub 'su - ${UserName} -c "sudo aws s3 cp s3://${BucketName}/${Thing}/${CertificateName} ~/certs/pubsub/"'
          - !Sub 'su - ${UserName} -c "sudo aws s3 cp s3://${BucketName}/${Thing}/${PrivateKeyName} ~/certs/pubsub/"'
          - !Sub 'su - ${UserName} -c "sudo aws s3 cp s3://${BucketName}/${Thing}/${PublicKeyName} ~/certs/pubsub"'
          - !Sub 'su - ${UserName} -c "sudo chown ${UserName}:${UserName} ~/certs/pubsub/*"'
          
          - !Sub 'su - ${UserName} -c "sudo chmod 644 ~/certs/pubsub/*"'
          - !Sub 'su - ${UserName} -c "sudo chmod 600 ~/certs/pubsub/${PrivateKeyName}"'
          
          - !Sub 'su - ${UserName} -c "mkdir ~/.aws-iot-device-client"'
          - !Sub 'su - ${UserName} -c "mkdir ~/.aws-iot-device-client/log"'
          - !Sub 'su - ${UserName} -c "chmod 745 ~/.aws-iot-device-client/log"'
          - !Sub 'su - ${UserName} -c "echo " " > ~/.aws-iot-device-client/log/aws-iot-device-client.log"'
          - !Sub 'su - ${UserName} -c "echo " " > ~/.aws-iot-device-client/log/pubsub_rx_msgs.log"'
          - !Sub 'su - ${UserName} -c "chmod 600 ~/.aws-iot-device-client/log/*"'
          
          - !Sub |
            cat << EOF > /home/${UserName}/messages/sample-ws-message.json
            {
              "temperature": 28,
              "humidity": 80,
              "barometer": 1013,
              "wind": {
                "velocity": 22,
                "bearing": 255
              }
            }
            EOF
          - !Sub 'su - ${UserName} -c "sudo chown ${UserName}:${UserName} ~/messages/sample-ws-message.json"'
          - !Sub 'su - ${UserName} -c "chmod 600 ~/messages/*"'
          
          - !Sub 'su - ${UserName} -c "chmod 745 ~/dc-configs"'
          - !Sub |
            cat << EOF > /home/${UserName}/dc-configs/dc-pubsub-custom-config.json
            {
              "endpoint": "${Endpoint}",
              "cert": "~/certs/pubsub/${CertificateName}",
              "key": "~/certs/pubsub/${PrivateKeyName}",
              "root-ca": "~/certs/AmazonRootCA1.pem",
              "thing-name": "${Thing}",
              "logging": {
                "enable-sdk-logging": true,
                "level": "DEBUG",
                "type": "STDOUT",
                "file": ""
              },
              "jobs": {
                "enabled": false,
                "handler-directory": ""
              },
              "tunneling": {
                "enabled": false
              },
              "device-defender": {
                "enabled": false,
                "interval": 300
              },
              "fleet-provisioning": {
                "enabled": false,
                "template-name": "",
                "template-parameters": "",
                "csr-file": "",
                "device-key": ""
              },
              "samples": {
                "pub-sub": {
                  "enabled": true,
                  "publish-topic": "${PublishTopicName}",
                  "publish-file": "~/messages/sample-ws-message.json",
                  "subscribe-topic": "${SubscribeTopicName}",
                  "subscribe-file": "~/.aws-iot-device-client/log/pubsub_rx_msgs.log"
                }
              },
              "config-shadow": {
                "enabled": false
              },
              "sample-shadow": {
                "enabled": false,
                "shadow-name": "",
                "shadow-input-file": "",
                "shadow-output-file": ""
              }
            }
            EOF
          - !Sub 'su - ${UserName} -c "sudo chown ${UserName}:${UserName} ~/dc-configs/dc-pubsub-config.json"'
          - !Sub 'su - ${UserName} -c "chmod 644 ~/dc-configs/dc-pubsub-config.json"'
          
          - !Sub 'su - ${UserName} -c "sudo mkdir /var/log/aws-iot-device-client"'
          - !Sub 'su - ${UserName} -c "sudo chmod 745 /var/log/aws-iot-device-client"'
          - !Sub 'su - ${UserName} -c "sudo chown ${UserName}:${UserName} /var/log/aws-iot-device-client"'
      Targets:
        - Key: InstanceIds
          Values:
            - !Ref InstanceId
      WaitForSuccessTimeoutSeconds: !Ref WaitForSuccessTimeoutSeconds
Code language: YAML (yaml)

There are three main changes from the page introduced at the beginning of this report.

The first point is a process related to the .aws-iot-device-client directory.
This directory is for logs generated when messages are sent and received using the AWS IoT Device Client.
After creating this directory, create the log file as well.

The second point is to create sample-ws-message.json.
This corresponds to the content of the MQTT message to be sent to AWS IoT Core using AWS IoT Device Client.

The third point is to create dc-pubsub-custom-config.json.
Originally, dc-pubsub-config.json was used, but this file is created by modifying it.
The changes from the original file are as follows: When a message is sent, the contents of sample-ws-message.json is sent, and when a message is received, the received message is written to the log file (pubsub_rx_msgs.log) under the .aws-iot-device-client directory.When a message is received, the message is written to a log file under the .awsub_rx_msgs.log directory.

Architecting

Registering the Raspberry Pi with SSM

Create the first CloudFormation stack.

Create a CloudFormation stack using the AWS CLI.
After placing the above template file in any S3 bucket, execute the following command

$ aws cloudformation create-stack \
--stack-name fa-155-01 \
--template-url https://[bucket-name].s3.[region].amazonaws.com/fa-155/fa-155-01.yaml \
--capabilities CAPABILITY_IAM
Code language: Bash (bash)

For more information on creating stacks, please see the following page.

あわせて読みたい
CloudFormation’s nested stack 【How to build an environment with a nested CloudFormation stack】 Examine nested stacks in CloudFormation. CloudFormation allows you to nest stacks. Nested ...

This stack primarily creates the following resources

  • S3 bucket to place client certificates and keys
  • SSM Hybrid Activation
  • IAM role for activation

Once the stack has been created, you will receive a hybrid activation code and ID as shown below.

Detail of SSM 01.

Install SSM Agent on Raspberry Pi

On the Raspberry Pi, run the following command to install SSM Agent.

sudo apt-get -y update
sudo apt-get -y upgrade
sudo apt-get -y install libc6:armhf
mkdir /tmp/ssm
curl https://amazon-ssm-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/debian_arm/ssm-setup-cli -o /tmp/ssm/ssm-setup-cli
sudo chmod +x /tmp/ssm/ssm-setup-cli
sudo /tmp/ssm/ssm-setup-cli -register -activation-code "[activation-code]" -activation-id "[activation-id]" -region "ap-northeast-1"
Code language: Bash (bash)

Embed the activation ID and code you identified earlier in the last command.

Please refer to the following page for details on the procedure.

あわせて読みたい
After setting up the Raspberry Pi, register it in Systems Manager and run commands from AWS 【After setting up the Raspberry Pi, register it in Systems Manager and run commands from AWS】 AWS Systems Manager can manage not only EC2 instances, but al...

Checking SSM Fleet Manager, we see that the SSM agent is indeed installed and managed on the Raspberry Pi.

Detail of SSM 02.

Set up AWS IoT Device Client after registering Raspberry Pi to AWS IoT using SSM documentation

Create a second CloudFormation stack.

Create a stack using the AWS CLI as before.

$ aws cloudformation create-stack \
--stack-name fa-155-02 \
--template-url https://[bucket-name].s3.[region].amazonaws.com/fa-155/fa-155-02.yaml \
--capabilities CAPABILITY_IAM
Code language: Bash (bash)

This stack primarily creates the following resources

  • IoT Thing
  • IoT Policy
  • Client Certificates and Keys
  • Attach client certificates to Thing and IoT policy

In addition, the SSM document will download the client certificate and key to the Raspberry Pi, allowing the Raspberry Pi to be treated as a Thing.
The necessary steps to use the AWS IoT Device Client are then performed.

Check the resources created from the management console.

Identify resources related to AWS IoT.

Detail of AWS IoT 01.
Detail of AWS IoT 02.
Detail of AWS IoT 03.

Thing, certificate, and policy have been successfully created.

Operation Check

Check the installation status of AWS IoT Device Client

Now that you are ready, access the Raspberry Pi.
Access is done via SSH from the local machine.

Check the availability of certificates and keys.

awstut@raspberrypi:~ $ ls -l ~/certs/pubsub/
total 12
-rw-r--r-- 1 awstut awstut 1220 Mar 27 21:13 device.pem.crt
-rw------- 1 awstut awstut 1675 Mar 27 21:13 private.pem.key
-rw-r--r-- 1 awstut awstut  451 Mar 27 21:13 public.pem.key
Code language: Bash (bash)

Indeed, the certificate and key are downloaded from the S3 bucket.
This means that this Raspberry Pi can act as an AWS IoT device.

Check the installation status of AWS IoT Device Client.

awstut@raspberrypi:~ $ cd ~/aws-iot-device-client/build/
awstut@raspberrypi:~/aws-iot-device-client/build $ ./aws-iot-device-client --version
v1.9.2-cf76107
Code language: Bash (bash)

You can see that the AWS IoT Device Client is indeed installed and ready to use.

Send messages using AWS IoT Device Client

Send a message according to the following page.

あわせて読みたい
AWS IoT Device Client でのメッセージの発行のデモンストレーション - AWS IoT Core AWS IoT Device Client がデフォルトおよびカスタムMQTTメッセージを送信する方法について説明します。
awstut@raspberrypi:~/aws-iot-device-client/build $ ./aws-iot-device-client --config-file ~/dc-configs/dc-pubsub-config.json
2024-03-30T10:30:33.123Z [WARN]  {FileUtils.cpp}: Permissions to given file/dir path '/home/awstut/dc-configs/dc-pubsub-config.json' is not set to recommended value... {Permissions: {desired: 640, actual: 644}}
2024-03-30T10:30:33.124Z [INFO]  {Config.cpp}: Successfully fetched JSON config file: {
  "endpoint": "a2oxckhng7gmur-ats.iot.ap-northeast-1.amazonaws.com",
  "cert": "~/certs/pubsub/device.pem.crt",
  "key": "~/certs/pubsub/private.pem.key",
  "root-ca": "~/certs/AmazonRootCA1.pem",
  "thing-name": "fa-155-thing",
  "logging": {
    "enable-sdk-logging": true,
    "level": "DEBUG",
    "type": "STDOUT",
    "file": ""
  },
  "jobs": {
    "enabled": false,
    "handler-directory": ""
  },
  "tunneling": {
    "enabled": false
  },
  "device-defender": {
    "enabled": false,
    "interval": 300
  },
  "fleet-provisioning": {
    "enabled": false,
    "template-name": "",
    "template-parameters": "",
    "csr-file": "",
    "device-key": ""
  },
  "samples": {
    "pub-sub": {
      "enabled": true,
      "publish-topic": "test/dc/pubtopic",
      "publish-file": "~/messages/sample-ws-message.json",
      "subscribe-topic": "test/dc/subtopic",
      "subscribe-file": "~/.aws-iot-device-client/log/pubsub_rx_msgs.log"
    }
  },
  "config-shadow": {
    "enabled": false
  },
  "sample-shadow": {
    "enabled": false,
    "shadow-name": "",
    "shadow-input-file": "",
    "shadow-output-file": ""
  }
}

2024-03-30T10:30:33.124Z [INFO]  {FileUtils.cpp}: Successfully create directory /home/awstut/.aws-iot-device-client/sample-shadow/ with required permissions 700
2024-03-30T10:30:33.124Z [INFO]  {Config.cpp}: ~/.aws-iot-device-client/sample-shadow/default-sample-shadow-document
2024-03-30T10:30:33.124Z [INFO]  {Config.cpp}: Succesfully create default file: /home/awstut/.aws-iot-device-client/sample-shadow/default-sample-shadow-document required for storage of shadow document
2024-03-30T10:30:33.124Z [DEBUG] {Config.cpp}: Did not find a runtime configuration file, assuming Fleet Provisioning has not run for this device
2024-03-30T10:30:33.124Z [DEBUG] {Config.cpp}: Did not find a http proxy config file /home/awstut/.aws-iot-device-client/http-proxy.conf, assuming HTTP proxy is disabled on this device
2024-03-30T10:30:33.124Z [DEBUG] {EnvUtils.cpp}: Updated PATH environment variable to: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/home/awstut/.aws-iot-device-client:/home/awstut/.aws-iot-device-client/jobs:/home/awstut/aws-iot-device-client/build:/home/awstut/aws-iot-device-client/build/jobs
2024-03-30T10:30:33.124Z [DEBUG] {LockFile.cpp}: creating lockfile
2024-03-30T10:30:33.124Z [INFO]  {Main.cpp}: Now running AWS IoT Device Client version v1.9.2-cf76107
2024-03-30T10:30:33.124Z [INFO]  {SharedCrtResourceManager.cpp}: SDK logging is enabled. Check /var/log/aws-iot-device-client/sdk.log for SDK logs.
2024-03-30T10:30:33.124Z [DEBUG] {Retry.cpp}: Retryable function starting, it will retry until success
2024-03-30T10:30:33.174Z [INFO]  {SharedCrtResourceManager.cpp}: Establishing MQTT connection with client id fa-155-thing...
2024-03-30T10:30:33.363Z [INFO]  {SharedCrtResourceManager.cpp}: MQTT connection established with return code: 0
2024-03-30T10:30:33.363Z [INFO]  {SharedCrtResourceManager.cpp}: Shared MQTT connection is ready!
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Provisioning with Secure Elements is disabled
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Config shadow is disabled
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Jobs is disabled
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Secure Tunneling is disabled
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Device Defender is disabled
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Sample shadow is disabled
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: PubSub is enabled
2024-03-30T10:30:33.363Z [INFO]  {samples/PubSubFeature.cpp}: Creating Pub/Sub file: /home/awstut/messages/sample-ws-message.json
2024-03-30T10:30:33.363Z [INFO]  {samples/PubSubFeature.cpp}: Creating Pub/Sub file: /home/awstut/.aws-iot-device-client/log/pubsub_rx_msgs.log
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Sensor Publish is disabled
2024-03-30T10:30:33.363Z [INFO]  {SharedCrtResourceManager.cpp}: Starting Device Client features.
2024-03-30T10:30:33.363Z [DEBUG] {FeatureRegistry.cpp}: Attempting to start Pub Sub Sample
2024-03-30T10:30:33.363Z [INFO]  {samples/PubSubFeature.cpp}: Starting Pub Sub Sample
2024-03-30T10:30:33.363Z [INFO]  {Main.cpp}: Client base has been notified that Pub Sub Sample has started
2024-03-30T10:30:33.399Z [DEBUG] {samples/PubSubFeature.cpp}: PublishCompAck: PacketId:(Pub Sub Sample), ErrorCode:0
2024-03-30T10:30:33.417Z [DEBUG] {samples/PubSubFeature.cpp}: SubAck: PacketId:(Pub Sub Sample), ErrorCode:0
Code language: Bash (bash)

The log shows that MQTT messages were successfully sent.

Then check the MQTT test client page of the Managed Console.

Detail of AWS IoT 04.

Indeed, a message is sent to test/dc/pubtopic.
Looking at the content, we can see that it is indeed the content specified in sample-ws-message.json.
Thus, it is possible to send any message using the AWS IoT Device Client.

Receive messages using AWS IoT Device Client

Continue to receive messages according to the page.

あわせて読みたい
Demonstrate subscribing to messages with the AWS IoT Device Client - AWS IoT Core Learn how the AWS IoT Device Client can send default and custom MQTT messages.

Since the AWS IoT Device Client is already running, send a message to test/dc/subtopic on the MQTT test client page of the managed console.

Detail of AWS IoT 05.

The Raspberry Pi running the AWS IoT Device Client will then notify you of the receipt of the message.

2024-03-30T10:40:51.339Z [DEBUG] {samples/PubSubFeature.cpp}: Message received on subscribe topic, size: 45 bytes
Code language: Bash (bash)

Stop AWS IoT Device Client and check the log file.

$ cat ~/.aws-iot-device-client/log/pubsub_rx_msgs.log
{
  "message": "Hello from AWS IoT console"
}
Code language: Bash (bash)

It is indeed the message sent on the MQTT test client page.
Thus, it is possible to receive messages using the AWS IoT Device Client.

Summary

We have identified how to send and receive messages on the Raspberry Pi using the AWS IoT Device Client.

TOC