IoT/IIoT


The G3 module embedded software image includes components enabling its use in Internet of Things and/or Industrial Internet of Things applications. these components are controlled by the standard chkconfig command and are disabled by default.

Note

In general, IoT/IIoT applications will require Trusted Platform Module (TPM) hardware to be installed in the G3 module. This is standard on the G3MTBR which is intended for IoT gateway applications. All other modules support the addition of a TPM on an application specific daughter card via the I2C bus.

The following sections discuss enabling and configuring the IoT/IIoT related sofware components.

TPM

Getting Started with the Trusted Platform Module (TPM)

Note

The following instructions require the use of your favorite terminal based text editor. If you do not have a preferred text editor, vim and Gnu nano come pre-installed. If you are not already familiar with vim, we recommend that you stick with Gnu nano. You can find a cheat sheet at the Gnu nano website.

  1. To start, run the following commands in your bash shell while logged into the target as root…

1# Set the DTB to one that supports TPM2 and reboot.
2fw_setenv mender_dtb_name stm32mp1-g3mtbr-none.dtb
3reboot
4
5# Add TPM2 PKCS11 Store environment variable to .bashrc.
6# This enables using the TPM2 in your current shell environment.
7echo "export TPM2_PKCS11_STORE=/data/opt/tpm2-pkcs11/" >> ~/.bashrc
8source ~/.bashrc
  1. Configure OpenSSL to use the Trusted Platform Module (TPM) by adding the settings below to /etc/ssl/openssl.cnf beneath HOME = . on line 13 and before # Extra OBJECT IDENTIFIER info.

 1# Add support for the TPM2
 2openssl_conf = openssl_init
 3[openssl_init]
 4engines=engine_section
 5
 6[engine_section]
 7pkcs11 = pkcs11_section
 8
 9[pkcs11_section]
10engine_id = pkcs11
11dynamic_path = /usr/lib/engines-1.1/pkcs11.so
12MODULE_PATH = /usr/lib/libtpm2_pkcs11.so.0
13init = 0

Connecting to AWS Greengrass V1

Add TPM2_PKCS11_STORE to the Greengrass init.d service so the file looks like below. The TPM2 will not work correctly with Greengrass on boot unless the environment variable TPM2_PKCS_STORE is defined and configured beforehand:

Error

Nick - What is the path to the GG init script?

 1#!/bin/sh
 2#           levels  start   kill
 3#===================================
 4# chkconfig:        45      80      20
 5# description:  AWS IoT Greengrass
 6
 7export TPM2_PKCS11_STORE=/data/opt/tpm2-pkcs11/
 8GG_LAUNCHER="$(find /data/greengrass -type f -name greengrassd)"
 9
10case "${1}" in
11    start | stop | restart)
12            ${GG_LAUNCHER} ${1}
13    ;;
14    *)
15    echo "Usage: $0 {start|stop|restart}"
16    exit 1
17    ;;
18esac
  1. Run:

1/usr/bin/tpm2-gg-setup.sh
  1. Copy the generated device certificate to your host computer:

1scp root@<ip-address>:/data/greengrass/certs/deviceCert.csr .

Important

You will need to substitute the IP address of your target in the command above.

  1. Upload your device certificate and associate it with your Greengrass Core policy:

    • On the left, under AWS IOT, select Secure->Certificates then on the right select Add certificate->Create certificate.

    • Select “Create certificate with certificate signing request (CSR)” then upload your deviceCert.csr file from the previous step and select Create.

    • If successful, a pop-up will appear prompting you to download the results. Download both the Device certificate and the RSA Amazon trust services endpoint, and copy both of them to /data/greengrass/certs on your target.

    • Activate the new certificate by checking its box on the left and selecting Actions->Activate.

    • Select your newly created certificate and select Attach policies then select your Greengrass core’s associated policy and select Attach policies

  2. Edit the Greengrass configuration file, /data/greengrass/config/config.json, so the following fields match:

 1"runtime" : {
 2    "cgroup" : {
 3       "useSystemd" : "no"
 4    },
 5},
 6"crypto": {
 7    "caPath" :  "file:///data/greengrass/certs/root.ca.pem",
 8    "PKCS11": {
 9       "OpenSSLEngine": "/usr/lib/engines-1.1/pkcs11.so",
10       "P11Provider": "/usr/lib/libtpm2_pkcs11.so.0",
11       "slotLabel": "greengrass",
12       "slotUserPin": "123456"
13    },
14    "principals": {
15        "SecretsManager" : {
16            "privateKeyPath" : "file:///data/greengrass/certs/hash-setup.private.key"
17        },
18        "IoTCertificate" : {
19            "privateKeyPath" : "file:///data/greengrass/certs/hash-setup.private.key",
20            "certificatePath" : "file:///data/greengrass/certs/hash-setup.cert.pem"
21        },
22        "MQTTServerCertificate" : {
23            "privateKeyPath" : "file:///data/greengrass/certs/hash-setup.private.key",
24            "certificatePath" : "file:///data/greengrass/certs/hash-setup.cert.pem"
25        }
26    }
27}
  1. Restart Greengrass and test local MQTT broker to AWS Cloud connection

AWS Greengrass

Warning

A credit card is necessary to sign up for AWS, even though it’s free to use if you stay under the AWS Free Tier limits.

The following documentation is meant as a suppliment to the official AWS Greengrass V1 documentation. We recommend first reviewing Amazon’s documentation to get the most value out of our documentation.

Interacting with the AWS Greengrass Daemon

You can perform the following actions in your bash shell on the target:

  • Start/Stop/Restart:

1/etc/init.d/greengrass start|stop|restart
1tail -f /data/greengrass/ggc/var/log/system/runtime.log
1tail -f /data/greengrass/ggc/var/log/*/*/*.log

Getting Started with the AWS Greengrass Daemon

  1. Create the Greengrass Group and Core. Follow this procedure from AWS EXACTLY! Adjust the Group and Core names for your use. Stop when it instructs you to install Greengrass software (step 11) because the Greengrass software is already installed and ready to be configured.

Error

Nick - step 11? there is no step 11 here… is this in the referenced doc? If yes, there should be a hyperlink to it.

  1. Configure Greengrass Group:

    When running AWS IoT Greengrass initially without Docker, all Lambda functions must run without containerization. In this step, set the default containerization for the group to No container. Do this before you deploy the group for the first time.

    • In the AWS IoT console, choose Greengrass, and then choose Groups.

    • Choose the group whose settings you want to change.

    • Choose Settings.

    • Under Lambda runtime environment, choose No container.

    • Choose Update default Lambda execution configuration. Review the message in the confirmation window, and then choose Continue.

  1. Download your AWS core security resources and copy them to your gateway. Replace hash-setup with the file you downloaded in step 1:

1scp hash-setup.tar.gz root@<ip-address>:/data/greengrass

Important

You will need to substitute the IP address of your target in the command above.

  1. Untar your AWS core security resources (from step 3) to /data/greengrass:

1tar zxvf /data/greengrass/hash-setup.tar.gz -C /data/greengrass/
  1. Edit the Greengrass config file, /data/greengrass/config/config.json, so the following fields match:

 1"runtime" : {
 2  "cgroup" : {
 3    "useSystemd" : "no"
 4  }
 5},
 6"crypto" : {
 7  "principals" : {
 8    "SecretsManager" : {
 9      "privateKeyPath" : "file:///data/greengrass/certs/hash-setup.private.key"
10    },
11    "IoTCertificate" : {
12      "privateKeyPath" : "file:///data/greengrass/certs/hash-setup.private.key",
13      "certificatePath" : "file:///data/greengrass/certs/hash-setup.cert.pem"
14    }
15  },
16  "caPath" : "file:///data/greengrass/certs/root.ca.pem"
17}
  1. Create a lambda function in Greengrass by following these instructions. Step 10 is optional since aliases are not required.

    Error

    Nick - step 10? there is no step 10 here… is this in the referenced doc? If yes, there should be a hyperlink to it.

    • When creating your Python lambda, make sure to choose the python3.8 runtime

    • Under Basic settings, your Handler name must match the convention: filname.name_of_function_handle

  2. Configure your newly added lambda function using these instructions, stopping at step 15.

    Error

    Nick - step 15? there is no step 15 here… is this in the referenced doc? If yes, there should be a hyperlink to it.

    • In step 7, you don’t have to set the timeout to 25, but make sure you remember to change the Lambda Lifecycle to Make this function long-lived and keep it running indefinitely

      Error

      Nick - step 7? we’re in step 7 here… is this in the referenced doc? If yes, there should be a hyperlink to it.

  3. Deploy your lambda using these instructions.

  4. Verify that the lambda is running on the core device using these instructions.

Connecting Greengrass to a MQTT Broker

By default, the G3 module platform runs mosquitto for its local MQTT broker, but other MQTT brokers exist as well. Below are basic instructions to connect the local mosquitto broker to AWS Greengrass in order to forward MQTT messages to and from the AWS Cloud:

  1. Ensure that mosquitto and Greengrass are running by checking the output of the following commands:

1/etc/init.d/mosquitto status
2ps -elf | grep greengrass
  1. Using the skills you learned in Getting Started, copy the code below and create a new lambda in a file named MqttClient.py. Under “Basic settings”, your Handler name will be MqttClient.function_handler:

  1import logging
  2import os
  3import json
  4from threading import Timer
  5
  6import greengrasssdk
  7import paho.mqtt.client as mqtt
  8
  9# Creating a greengrass core sdk client
 10iot_data = greengrasssdk.client('iot-data')
 11
 12logger = logging.getLogger(__name__)
 13logger.setLevel(logging.INFO)
 14streamHandler = logging.StreamHandler()
 15formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 16streamHandler.setFormatter(formatter)
 17logger.addHandler(streamHandler)
 18
 19GROUP_ID = None
 20THING_NAME = None
 21THING_ARN = None
 22HOST = 'localhost'
 23PORT = 1883
 24USERNAME = None
 25PASSWORD = None
 26MQTT_SUB = "#"
 27TIMER_INTERVAL = 1
 28
 29if 'USERNAME' in os.environ:
 30    USERNAME = os.environ['USERNAME']
 31
 32if 'PASSWORD' in os.environ:
 33    PASSWORD = os.environ['PASSWORD']
 34
 35# The callback for when the client receives a CONNACK response from the server.
 36def on_connect(client, userdata, flags, rc):
 37    logger.info("Connected with result code " + str(rc))
 38
 39    # Subscribing in on_connect() means that if we lose the connection and
 40    # reconnect then subscriptions will be renewed.
 41    client.subscribe(MQTT_SUB)
 42
 43# The callback for when a PUBLISH message is received from the server.
 44def on_message(client, userdata, msg):
 45    logger.info('on_message received')
 46    topic = msg.topic
 47
 48    # Publish the message to the MQTT server
 49    logger.info('Publishing message to |GG| from broker on topic [' + topic + ']')
 50
 51    payload = msg.payload
 52    try:
 53        json_payload = json.dumps(str(payload.decode("utf-8")))
 54    except UnicodeDecodeError:
 55        payload = payload.hex()
 56
 57    try:
 58        iot_data.publish(topic=topic, payload=payload)
 59    except Exception as error:
 60        logger.error('An exception occurred: {}'.format(error))
 61
 62
 63mqtt_client = mqtt.Client()
 64mqtt_client.on_connect = on_connect
 65mqtt_client.on_message = on_message
 66
 67mqtt_client.username_pw_set(USERNAME, PASSWORD)
 68
 69def greengrass_mqtt_client_loop():
 70    error = None
 71
 72    try:
 73        mqtt_client.connect(HOST, PORT, 60)
 74        # Blocking call that processes network traffic, dispatches callbacks
 75        # and handles reconnecting.
 76        mqtt_client.loop_forever()
 77        logger.info('Should never get Here')
 78    except ConnectionRefusedError as e:
 79        # Connection refused, try connecting again in 5 seconds
 80        error = ('Connection to the MQTT server failed [' + str(e) + '], '
 81                 'make sure it is running and the settings are correct')
 82    except Exception as e:
 83        # Something else went wrong
 84        error = 'Something went wrong [' + str(e) + ']'
 85
 86    # If we get here we'll start log the error, if any, and loop again
 87    if error is not None: logger.error(error)
 88    logger.error('Reconnecting')
 89    Timer(TIMER_INTERVAL, greengrass_mqtt_client_loop).start()
 90
 91# Asynchronously schedule this function to run in TIMER_INTERVAL seconds.
 92# We don't call the function immediately in case the MQTT configuration
 93# is incorrect.
 94Timer(TIMER_INTERVAL, greengrass_mqtt_client_loop).start()
 95
 96# This is invoked when a message is received from |GG|
 97def function_handler(event, context):
 98    try:
 99        inbound_topic = context.client_context.custom['subject']
100
101        # Publish the message to the MQTT server
102        logger.info('Publishing message to broker from |GG| on topic [' +
103                    inbound_topic + ']')
104
105        mqtt_client.publish(inbound_topic, json.dumps(event))
106    except Exception as error:
107        logger.error('An exception occurred: {}'.format(error))
108
109    return
  1. Add MQTT topic subscriptions to lambda function(s) to transport MQTT data to and from the local MQTT broker and the AWS Cloud and vice versa. This step and the following steps use the MQTT topics of foo and bar as an example, as seen below:

    Source

    Target

    Topic

    MqttLambda

    IoT Cloud

    foo

    IoT Cloud

    MqttLambda

    bar

  2. Deploy the lambda to the Greengrass Core.

  3. Verify MQTT traffic from local broker to AWS Cloud:

1mosquitto_pub -h <ip_address> -t foo -m "from local broker"

Important

You will need to substitute the IP address of your target in the command above.

  1. Now check the AWS IoT Test Console to check if the message on topic foo was received.

  2. Verify MQTT traffic from AWS Cloud to local broker:

1mosquitto_sub -h <ip_address> -v -t bar

Important

You will need to substitute the IP address of your target in the command above.

  1. Send an MQTT message on topic bar from the AWS IoT Test Console and check the output of mosquitto_sub to see if the local broker recieved the MQTT message.