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 Client is free, open-source, modular software written in C++ that you can compile and install on your Embedded Linux based IoT devices to access AWS IoT Core, AWS IoT Device Management, and AWS IoT Device Defender features by default. It serves as a reference implementation for your IoT devices to work with AWS IoT services, with operational best practices baked in – using it is the easiest way to create a proof-of-concept (PoC) for your IoT project.

aws-iot-device-client

This time, we will follow the official AWS tutorial and install the AWS IoT Device Client on a Raspberry Pi.

あわせて読みたい
Tutorial: Installing and configuring the AWS IoT Device Client - AWS IoT Core This tutorial walks you through the installation and configuration of the AWS IoT Device Client and the creation of AWS IoT resources that you'll use in this an...

The Raspberry Pi to be used will be registered with Systems Manager.
This is to send commands through SSM to install the AWS IoT Device Client.

Environment

Diagram of Installing the AWS IoT Device Client on the Raspberry Pi registered in Systems Manager.

The composition is divided into two main parts.

The first is for registering the Raspberry Pi with Systems Manager.
Run the Lambda function associated with the CloudFormation custom resource to create a hybrid activation for registration.

The second is related to AWS IoT.
The Lambda function is used to create the resources needed to register the Raspberry Pi as an IoT device.
This function is also associated with a custom resource.

The generated resources will include client certificates and keys, which will be placed in an S3 bucket.
This is to allow the Raspberry Pi to download these resources.

From the AWS side, send commands to the Raspbbery Pi to set up the AWS IoT Device Client.
Specifically, this takes the form of creating an SSM association to the Raspberry Pi and running a shell script.

The runtime environment for Lambda functions is Python 3.12.

CloudFormation template files

In the above configuration, CloudFormation is used to build the AWS-side configuration.
The CloudFormation templates are placed at the following URL

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

Registering the Raspberry Pi with SSM

Changes to IAM Roles for SSM

Register your Rraspberry Pi with SSM.
Registration is a two-step process.

  1. Create a hybrid activation for Systems Manager
  2. Install SSM agent on Raspberry Pi while using activation code

Please refer to the following page for specific procedures.

あわせて読みたい
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...

What differs from the above page is the IAM role for SSM.

Resources:
  SSMServiceRole:
    Type: AWS::IAM::Role
    DeletionPolicy: Delete
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - ssm.amazonaws.com
            Condition:
              StringEquals:
                aws:SourceAccount: !Ref AWS::AccountId
              ArnEquals:
                aws:SourceArn: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:*"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Policies:
        - PolicyName: SSMServiceRolePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource:
                  - !Sub "arn:aws:s3:::${BucketName}/*"
Code language: YAML (yaml)

This IAM role defines the AWS actions that the Raspberry Pi can perform.
In this case, we will allow access to the S3 bucket.

This bucket has two uses.
The first is used to install certificates and keys for AWS IoT.
These objects will be downloaded and used by the Raspberry Pi, so allow s3:GetObject.

The second is used to place the execution log for the SSM association.
Since the logs will be placed from the Raspberry Pi, s3:PutObject is allowed.

CloudFormation Stacks Creation

Create a CloudFormation stack using the AWS CLI.
Place the above template files in any S3 bucket and then execute the following command

$ aws cloudformation create-stack \
--stack-name fa-153-01 \
--template-url https://[bucket-name].s3.[region].amazonaws.com/fa-153/fa-153-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 ...

Check the relevant stack on the CloudFormation page of the Management Console.

Detail of CloudFormation 01.

We have indeed obtained a code and ID for hybrid activation.

Install SSM Agent on Raspberry Pi

Run the following command on the Raspberry Pi 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.

After the SSM Agent installation is successfully completed, the Agent will automatically start.

awstut@raspberrypi:~ $ sudo systemctl status amazon-ssm-agent
● amazon-ssm-agent.service - amazon-ssm-agent
      Loaded: loaded (/lib/systemd/system/amazon-ssm-agent.service; enabled; preset: enabled)
      Active: active (running) since Thu 2024-03-21 22:10:02 JST; 2 days ago
    Main PID: 2978 (amazon-ssm-agen)
      Tasks: 24 (limit: 9253)
        CPU: 6min 11.989s
      CGroup: /system.slice/amazon-ssm-agent.service
              ├─2978 /usr/bin/amazon-ssm-agent
              └─2996 /usr/bin/ssm-agent-worker
Code language: Bash (bash)

Check SSM Fleet Manager.

Detail of SSM 01.

Indeed, the Raspberry Pi is registered as a Managed Node.

Register your Raspberry Pi with AWS IoT

Obtain the instance ID assigned to the Raspberry Pi

Registering a Raspberry Pi as an IoT device with AWS IoT involves the following two processes

  1. Create an AWS IoT resource.
  2. Upload client certificate and key for AWS IoT from S3 bucket.

To register your Raspberry Pi with AWS IoT, create the following resources

  • Thing
  • IoT Policy
  • Client certificate
  • Private and Public Keys
  • Attachment of objects and certificates
  • Attach IoT policies and certificates

Please refer to the following page for specific procedures.

あわせて読みたい
Create AWS IoT client certificate using CloudFormation custom resource 【Create AWS IoT client certificate using CloudFormation custom resource】 As an introduction to AWS IoT Core, the following page reviews how to use an EC2 i...

The difference from the above page is the Lambda function that creates client certificates and keys.

Resources:
  Function2:
    Type: AWS::Lambda::Function
    Properties:
      Architectures:
        - !Ref Architecture
      Environment:
        Variables:
          ACTIVATION_ID: !Ref ActivationId
          BUCKET_NAME: !Ref BucketName
          CERTIFICATE_NAME: !Ref CertificateName
          PRIVATE_KEY_NAME: !Ref PrivateKeyName
          PUBLIC_KEY_NAME: !Ref PublicKeyName
          REGION: !Ref AWS::Region
          THING: !Ref Thing
      Code:
        ZipFile: |
          import boto3
          import cfnresponse
          import os
          
          activation_id = os.environ['ACTIVATION_ID']
          bucket_name = os.environ['BUCKET_NAME']
          certificate_name = os.environ['CERTIFICATE_NAME']
          private_key_name = os.environ['PRIVATE_KEY_NAME']
          public_key_name = os.environ['PUBLIC_KEY_NAME']
          region = os.environ['REGION']
          thing = os.environ['THING']
          
          s3_key = '{folder}/{object}'

          CREATE = 'Create'
          response_data = {}
          
          iot_client = boto3.client('iot', region_name=region)
          s3_client = boto3.client('s3', region_name=region)
          ssm_client = boto3.client('ssm', region_name=region)
        
          def lambda_handler(event, context):
            try:
              if event['RequestType'] == 'Create':
                iot_response = iot_client.create_keys_and_certificate(
                  setAsActive=True
                )

                s3_client.put_object(
                  Body=iot_response['certificatePem'],
                  Bucket=bucket_name,
                  Key=s3_key.format(
                    folder=thing,
                    object=certificate_name
                  )
                )
                
                # public key
                s3_client.put_object(
                  Body=iot_response['keyPair']['PublicKey'],
                  Bucket=bucket_name,
                  Key=s3_key.format(
                    folder=thing,
                    object=public_key_name
                  )
                )
                
                # private key
                s3_client.put_object(
                  Body=iot_response['keyPair']['PrivateKey'],
                  Bucket=bucket_name,
                  Key=s3_key.format(
                    folder=thing,
                    object=private_key_name
                  )
                )
                
                response_data['CertificateArn'] = iot_response['certificateArn']
                certificate_id = iot_response['certificateId']
                
                iot_endpoint_response = iot_client.describe_endpoint(
                  endpointType='iot:Data-ATS'
                )
                response_data['IoTEndpoint'] = iot_endpoint_response['endpointAddress']
                
                describe_instance_response = ssm_client.describe_instance_information(
                  Filters=[
                    {
                      'Key': 'ActivationIds',
                      'Values': [
                        activation_id
                      ]
                    }
                  ]
                )
                response_data['InstanceId'] = describe_instance_response['InstanceInformationList'][0]['InstanceId']
                
              elif event['RequestType'] == 'Delete':
                certificate_id = event['PhysicalResourceId']
              
                # delete objects in s3 bucket
                list_response = s3_client.list_objects_v2(
                  Bucket=bucket_name
                )
                
                if 'Contents' in list_response and len(list_response['Contents']):
                  for obj in list_response['Contents']:
                    delete_response = s3_client.delete_object(
                      Bucket=bucket_name,
                      Key=obj['Key']
                    )
                    print(delete_response)
                  
                # inactive and delete iot cert
                iot_client.update_certificate(
                  certificateId=certificate_id,
                  newStatus='INACTIVE'
                )
                iot_client.delete_certificate(
                  certificateId=certificate_id,
                  forceDelete=True
                )
                
              cfnresponse.send(
                event=event,
                context=context,
                responseStatus=cfnresponse.SUCCESS,
                responseData=response_data,
                physicalResourceId=certificate_id
                )
            except Exception as e:
              print(e)
              
              certificate_id = event['PhysicalResourceId']
              
              cfnresponse.send(
                event=event,
                context=context,
                responseStatus=cfnresponse.FAILED,
                responseData=response_data,
                physicalResourceId=certificate_id
                )
      FunctionName: !Sub "${Prefix}-function-02"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole2.Arn
      Timeout: !Ref Timeout
Code language: YAML (yaml)

The change is to get the instance ID assigned to the Raspberry Pi.
Execute the describe_instance_information method of the client object for SSM in boto3 to get the ID.
Search based on the ID of the hybrid activation.
The retrieved instance ID is used to create the SSM association described below.

Set up AWS IoT Device Client using SSM

The procedure for installing AWS IoT Device Client on a Raspberry Pi is basically the same as the procedure described on the official AWS page below.

あわせて読みたい
Tutorial: Installing and configuring the AWS IoT Device Client - AWS IoT Core This tutorial walks you through the installation and configuration of the AWS IoT Device Client and the creation of AWS IoT resources that you'll use in this an...

This time, however, instead of manually tracing the installation procedure, we will send commands from the AWS side to proceed with the setup automatically.
Specifically, we will create an SSM association and run the command through SSM Run Commands.

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 ~/policies"'
          - !Sub 'su - ${UserName} -c "mkdir ~/messages"'
          - !Sub 'su - ${UserName} -c "mkdir ~/certs/testconn"'
          - !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/testconn"'
          - !Sub 'su - ${UserName} -c "chmod 700 ~/certs/pubsub"'
          - !Sub 'su - ${UserName} -c "chmod 700 ~/certs/jobs"'
          
          - !Sub 'su - ${UserName} -c "sudo aws s3 cp s3://${BucketName}/${Thing}/${CertificateName} ~/certs/testconn/"'
          - !Sub 'su - ${UserName} -c "sudo aws s3 cp s3://${BucketName}/${Thing}/${PrivateKeyName} ~/certs/testconn/"'
          - !Sub 'su - ${UserName} -c "sudo aws s3 cp s3://${BucketName}/${Thing}/${PublicKeyName} ~/certs/testconn"'
          - !Sub 'su - ${UserName} -c "sudo chown ${UserName}:${UserName} ~/certs/testconn/*"'
          
          - !Sub 'su - ${UserName} -c "sudo chmod 644 ~/certs/testconn/*"'
          - !Sub 'su - ${UserName} -c "sudo chmod 600 ~/certs/testconn/${PrivateKeyName}"'
          
          - !Sub 'su - ${UserName} -c "chmod 745 ~/dc-configs"'
          - !Sub |
            cat << EOF > /home/${UserName}/dc-configs/dc-testconn-config.json
            {
              "endpoint": "${Endpoint}",
              "cert": "~/certs/testconn/${CertificateName}",
              "key": "~/certs/testconn/${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": "",
                  "subscribe-topic": "${SubscribeTopicName}",
                  "subscribe-file": ""
                }
              },
              "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-testconn-config.json"'
          - !Sub 'su - ${UserName} -c "chmod 644 ~/dc-configs/dc-testconn-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)

The SSM association executes the SSM document AWS-RunShellScript.
This document allows the specified command to be executed on the target instance.

The command we will be executing is the one discussed on the above page.
But with the following two changes

The first point uses the su command to specify the user who will execute each command.
As covered in detail on the following page, the user who executes the commands run by AWS-RunShellScript is root.

This time, the command will be executed against the Raspberry Pi, but this time as the user (awstut) specified during the Raspberry Pi OS installation.

The second point is about handling AWS IoT resources.
In the page introduced at the beginning of this chapter, the flow is to create things and IoT policies within the Raspberry Pi.
But in this configuration, they will be created using CloudFormation, so we will not execute any commands related to this.

The certificate and key are created by the Lambda function mentioned above and placed in the S3 bucket.
So we download them from the bucket using the AWS CLI.

CloudFormation Stacks Creation

Create a CloudFormation stack using the AWS CLI.
Place the above template file in any S3 bucket and then execute the following command

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

Resource Acknowledgement

Access the Management Console to see the resources that have been created.

Identify resources related to AWS IoT.

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

Thing, IoT policy, and certificate have been created.
And you can also see that the certificate is attached to the thing and policy.

Check the S3 bucket.

Detail of S3 01.

Indeed, the certificate and key are in place.
This means that the Lambda functions associated with the CloudFormation custom resources were automatically run when the stack was created and uploaded to this bucket after they were created.

Check Systems Manager.

Detail of SSM 02.

Looking at SSM State Manager, the SSM association is indeed created.

Next, check SSM Run Command.

Detail of SSM 03.

You can see that the command has indeed been executed against the Raspberry Pi.
From the above, we can see that the SSM document AWS-RunShellScript was used to send the commands related to the AWS IoT Device Client installation to the Raspbbery Pi and successfully. It means that it was completed successfully.

Operation Check

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/testconn
total 12
-rw-r--r-- 1 awstut awstut 1220 Mar 21 22:11 device.pem.crt
-rw------- 1 awstut awstut 1679 Mar 21 22:11 private.pem.key
-rw-r--r-- 1 awstut awstut  451 Mar 21 22:11 public.pem.key
Code language: Bash (bash)

Indeed, the certificate and key are downloaded from the S3 bucket.

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.

Finally, use the AWS IoT Device Client to send MQTT messages to the AWS IoT Core.
For sending the message, proceed as per the following page.

あわせて読みたい
Step 3: Configure the AWS IoT Device Client to test connectivity - AWS IoT Core The procedures in this section configure the AWS IoT Device Client to publish an MQTT message from your Raspberry Pi.
awstut@raspberrypi:~/aws-iot-device-client/build $ ./aws-iot-device-client --config-file ~/dc-configs/dc-testconn-config.json
2024-03-24T09:04:23.545Z [WARN]  {FileUtils.cpp}: Permissions to given file/dir path '/home/awstut/dc-configs/dc-testconn-config.json' is not set to recommended value... {Permissions: {desired: 640, actual: 644}}
2024-03-24T09:04:23.545Z [WARN]  {Config.cpp}: Key {publish-file} was provided in the JSON configuration file with an empty value
2024-03-24T09:04:23.545Z [WARN]  {Config.cpp}: Key {subscribe-file} was provided in the JSON configuration file with an empty value
2024-03-24T09:04:23.545Z [INFO]  {Config.cpp}: Successfully fetched JSON config file: {
  "endpoint": "a2oxckhng7gmur-ats.iot.ap-northeast-1.amazonaws.com",
  "cert": "~/certs/testconn/device.pem.crt",
  "key": "~/certs/testconn/private.pem.key",
  "root-ca": "~/certs/AmazonRootCA1.pem",
  "thing-name": "fa-153-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": "",
      "subscribe-topic": "test/dc/subtopic",
      "subscribe-file": ""
    }
  },
  "config-shadow": {
    "enabled": false
  },
  "sample-shadow": {
    "enabled": false,
    "shadow-name": "",
    "shadow-input-file": "",
    "shadow-output-file": ""
  }
}

2024-03-24T09:04:23.545Z [INFO]  {FileUtils.cpp}: Successfully create directory /home/awstut/.aws-iot-device-client/sample-shadow/ with required permissions 700
2024-03-24T09:04:23.545Z [INFO]  {Config.cpp}: ~/.aws-iot-device-client/sample-shadow/default-sample-shadow-document
2024-03-24T09:04:23.545Z [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-24T09:04:23.545Z [DEBUG] {Config.cpp}: Did not find a runtime configuration file, assuming Fleet Provisioning has not run for this device
2024-03-24T09:04:23.545Z [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-24T09:04:23.545Z [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-24T09:04:23.545Z [DEBUG] {LockFile.cpp}: creating lockfile
2024-03-24T09:04:23.545Z [INFO]  {Main.cpp}: Now running AWS IoT Device Client version v1.9.2-cf76107
2024-03-24T09:04:23.545Z [INFO]  {SharedCrtResourceManager.cpp}: SDK logging is enabled. Check /var/log/aws-iot-device-client/sdk.log for SDK logs.
2024-03-24T09:04:23.546Z [DEBUG] {Retry.cpp}: Retryable function starting, it will retry until success
2024-03-24T09:04:23.588Z [INFO]  {SharedCrtResourceManager.cpp}: Establishing MQTT connection with client id fa-153-thing...
2024-03-24T09:04:23.946Z [INFO]  {SharedCrtResourceManager.cpp}: MQTT connection established with return code: 0
2024-03-24T09:04:23.946Z [INFO]  {SharedCrtResourceManager.cpp}: Shared MQTT connection is ready!
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: Provisioning with Secure Elements is disabled
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: Config shadow is disabled
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: Jobs is disabled
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: Secure Tunneling is disabled
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: Device Defender is disabled
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: Sample shadow is disabled
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: PubSub is enabled
2024-03-24T09:04:23.946Z [INFO]  {samples/PubSubFeature.cpp}: Creating Pub/Sub file: /home/awstut/.aws-iot-device-client/pubsub/publish-file.txt
2024-03-24T09:04:23.946Z [INFO]  {samples/PubSubFeature.cpp}: Creating Pub/Sub file: /home/awstut/.aws-iot-device-client/pubsub/subscribe-file.txt
2024-03-24T09:04:23.946Z [INFO]  {Main.cpp}: Sensor Publish is disabled
2024-03-24T09:04:23.946Z [INFO]  {SharedCrtResourceManager.cpp}: Starting Device Client features.
2024-03-24T09:04:23.946Z [DEBUG] {FeatureRegistry.cpp}: Attempting to start Pub Sub Sample
2024-03-24T09:04:23.946Z [INFO]  {samples/PubSubFeature.cpp}: Starting Pub Sub Sample
2024-03-24T09:04:23.947Z [INFO]  {Main.cpp}: Client base has been notified that Pub Sub Sample has started
2024-03-24T09:04:23.975Z [DEBUG] {samples/PubSubFeature.cpp}: PublishCompAck: PacketId:(Pub Sub Sample), ErrorCode:0
2024-03-24T09:04:23.997Z [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.

After waiting with test/dc/pubtopic subscribed, the message was indeed sent.
This was sent by the AWS IoT Device Client on the Raspberry Pi.

Following the tutorial, I was indeed able to send a message using the AWS IoT Device Client.

Summary

We have installed the AWS IoT Device Client on the Raspberry Pi and have identified how to send test messages to the AWS IoT Core.
We were also able to set up the AWS IoT Device Client by registering the Raspberry Pi with Systems Manager and sending commands from SSM.