In this lab you will learn how to send commands to IoT devices using Cloud IoT Core Console and configure java sample code so that an IoT Core device subscribes to the command topic.

Commands are transitory, one-time directives sent to devices that are connected to Cloud IoT Core and subscribed to the commands topic.

Compared to device configurations, commands are faster and can be sent at large-volume to many devices simultaneously. Some examples include:

What You'll Learn

You will be opening multiple browser windows to observe graphical actions. Having a large monitor will be beneficial, but not required.

From the Navigation menu, select IoT Core:

Click Create a device registry:

Create a device registry with the following values:

Field

Value

Registry ID

my-registry

Region

us-central1

Protocol

MQTT

Default telemetry topic

Create a topic

Append my-device-events to the name and click Create.

Device state topic

Use the default value

Add CA certificate

Ignore

Click Create.

Later in the lab you will generate an RSA public/private key pair that will authenticate your MQTT device when it connects to Google Cloud.

Create multiple devices using IoT Core Console

In this section, you will create 3 virtual devices. The new virtual devices will be used for sending commands from the Google Cloud Shell.

  1. On the IoT Core page, click on Devices in the left menu, then click + Create a Device.

  2. Set the following fields:

Field

Value

Device ID

mqtt-device-1

Device Communication

Allow

Authentication

Default value (for now)

Public Key format

Default value (for now)

Public Key value

Default value (for now)

Device metadata

Default value

  1. Click Create.
  2. Click on the back arrow to return to the Devices page. Create additional devices with IDs mqtt-device-2 and mqtt-device-3 by repeating previous steps.

Click the back arrow at the top of the screen to see the devices listed on the Devices page:

  1. Open Cloud Shell:

Then click Start Cloud Shell.

  1. In Cloud Shell, run the following command to create an RS256 key:

openssl req -x509 -newkey rsa:2048 -keyout rsa_private.pem -nodes -out \
    rsa_cert.pem -subj "/CN=unused"
openssl pkcs8 -topk8 -inform PEM -outform DER -in rsa_private.pem \
    -nocrypt > rsa_private_pkcs8
  1. Go to Code Editor by clicking the pencil button on the top right of terminal.

  1. You'll see two files, rsa_cert.pem and rsa_private.pem.

  2. You can open the rsa_cert.pem file in the editor, or use this command:

cat rsa_cert.pem
  1. Copy the contents of rsa_cert.pem to the clipboard, include -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----.

Add public key to MQTT devices

Go back to the Console and click on the name of the first device.

On the Edit Device page, click Add public key.

Enter the following values:

Field

Value

Input method

Enter manually

Public key format

RS256_X509

Public key value

Paste contents of rsa_cert.pem

Public key expiration date

Default value

Your screen should look like this:

Click Add.

Repeat these steps for the other two MQTT devices.

Set environment variable for Cloud Shell

In Cloud Shell, set a PROJECT_ID variable, replacing <your-project-id> with the Project ID for this lab:

PROJECT_ID=<your-project-id>

Congratulations, you have set up Cloud Pub/Sub, created your device registry, and added multiple MQTT devices to the registry!

In Cloud Shell, clone the repo containing the mqtt example sample:

git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

Go into the manager folder:

cd java-docs-samples/iot/api-client/codelab/manager

Next, install the libraries and build the sample with Maven:

mvn clean compile assembly:single

If the build was successful, check if the libraries and sample installed properly by running the MqttExample script without passing any parameters:

mvn exec:java \
   -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo"

If the dependencies installed successfully, the program will print the following messages. For example:

Missing required options: project_id, registry_id, device_id, private_key_file, algorithm

Now that you have the program libraries installed, it's time to connect a single device to Cloud IoT Core.

  1. Copy the private key into local directory from root:

cp ~/rsa_private_pkcs8 .
  1. Run the following to connect to a single device over MQTT.

mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-1 \
                 -private_key_file=rsa_private_pkcs8 \
                 -algorithm=RS256"

If you see the following output, the device is successfully subscribed to config topic.

If you see any WARNING or ERROR messages, please check the following:

Now, you will edit the MqttCommandsDemo.java file to add code which will get the device subscribed to the command topic.

  1. In the Code Editor, open the java-docs-samples folder, then go to the iot/api-client/codelab/manager/src/main/java/com/example/cloud/iot/examples directory.
  2. Open the MqttCommandsDemo.java file.
  3. In the file, search for "begin code section".
  4. Add the following lines of code between the comments:In the Code Editor, click File > Save to save the file.
    String commandTopic = String.format("/devices/%s/commands/#", deviceId);
    System.out.println(String.format("Listening on %s", commandTopic));
  
    client.subscribe(commandTopic, 1);
  1. In Cloud Shell run the following Maven command to build and compile:
mvn clean compile assembly:single
  1. When the build is successful, it should display the following output.
  1. Subscribe your device to the command topic:

mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-1 \
                 -private_key_file=rsa_private_pkcs8 \
                 -algorithm=RS256"
  1. In the Google Cloud IoT Core console, choose Devices from the left menu.

  2. Click on the mqtt-device-1 device.
  3. Click Send Command button.

  1. Type some text into the Command data box then click Send Command.
  2. Your sent command should be displayed in the console: (Payload: <your-command>).
Payload:  <your-sent-command>

Make sure you send the command while the sample is running.

Now it's time to do more than printing out the command. Next, respond to a command by changing the color of the terminal.

  1. In the MqttCommandsDemo.java file, search for "begin command respond"
  2. Copy and paste the following Java code.
              /* Responding to a command message.
                 1) checking if it is a valid color.
                 2) If GUI thread already running, restart.
              */
              if (isValidColor(data, mainBgColor)) {
               mainBgColor = getColor((String) data.get("color"));
               if (mGUIthread != null && mGUIthread.isAlive()) mGUIthread.stop();
               mGUIthread =
                   new Thread(
                           () -> {
                             try {
                               startGui(mainScreen, mainBgColor);
                             } catch (IOException e) {
                               e.printStackTrace();
                             }
                           });
               mGUIthread.start();
              }
  1. Build and compile by running the following maven command:
mvn clean compile assembly:single

The code you just added will change the background color of the terminal as soon as a command with JSON string is received.

Choose to use either the Console or Cloud Shell to complete this next part.

(Option 1) Using the Console to change the color of your terminal

  1. Keep MQTT device subscribed to the command topic.
mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-1 \
                 -private_key_file=rsa_private_pkcs8 \
                 -algorithm=RS256"
  1. In the Console, click Send Command button from console.
  2. Type JSON formatted text:
{color: BLUE}
  1. Click Send Command.
  2. Make sure you send a command while your MQTT is subscribed to Commands topic.
  3. Check your Cloud Shell.

(Option 2) Using the gcloud command line to change the color of your terminal

  1. Keep MQTT device subscribed to the command topic.
mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-1 \
                 -private_key_file=rsa_private_pkcs8 \
                 -algorithm=RS256"
  1. Add a Cloud Shell tab by clicking the + in the ribbon:
  2. In the new tab, run the following command.
gcloud iot devices commands send --command-data={color:blue} --device=mqtt-device-1 --region=us-central1 --registry=my-registry
  1. Check the first Cloud Shell tab with the MQTT sample.

When you have multiple MQTT devices listening for commands, sending 1 command to all of them can make a simultaneous change. For example, you can control the colors of 100 lights in a large office using IoT Core commands, or orchestrate lights, heating, and cooling systems in a factory.

For this lab, you will change the color of all MQTT devices terminals at the same time.

First, disable tmux integration so you can use Cloud Shell in multiple tabs.

  1. Click the wrench icon in the Cloud Shell ribbon and select Tmux Settings.
  2. Uncheck the Enable tmux integration box
  3. Click OK.

Connect each MQTT device in a separate window

Next you will need 3 new browser tabs where you will run your current Cloud Shell link. To do this:

Align the browser tabs so you can see all three at the same time. Each browser tab will be one of the devices you've created. Be sure to run all of the connection commands in each tab.

  1. Set the environment variable in the new Cloud Shell:
PROJECT_ID="${DEVSHELL_PROJECT_ID:-Cloud Shell}"
  1. Go to manager folder:
cd java-docs-samples/iot/api-client/codelab/manager
  1. Connect the first device using MQTT:
mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-1 \
                 -private_key_file=rsa_private_pkcs8 \
 
                -algorithm=RS256"
  1. Connect the second MQTT device in the second tab:
mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-2 \
                 -private_key_file=rsa_private_pkcs8 \
                 -algorithm=RS256"
  1. Connect the third MQTT device in the third tab:
mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-3 \
                 -private_key_file=rsa_private_pkcs8 \
                 -algorithm=RS256"

If the sample is built successfully, the following section will show up with the output of the MQTT device that is being subscribed to commands and config topics, and starting to publish events messages:

Starting mqtt demo:
Listening on /devices/device-ec/commands/#
Listening on /devices/device-ec/config

Now you have configured all MQTT devices to connect to the command topic, next you will send commands to all devices at once.

Keep all MQTT devices connected to the commands topic

Make sure you place three browser windows with cloud shell vertically or horizontally parallel to see color changes at the same time.

  1. Open a new tab in Cloud Shell in the first terminal:

  1. Go to the manager folder of the sample:
cd java-docs-samples/iot/api-client/codelab/manager/

Run the following commands in the new Cloud Shell terminal to simultaneously change the background of all the terminals:

  1. Set the color by adding your choice - you get to choose from Black, blue, cyan, green, blue, magenta, red, white:
color=<your-chosen-color>
  1. Create a gcloud command-line script file for each MQTT device for sending a command:
for deviceId in 1 2 3
do
  echo "gcloud iot devices commands send --command-data={color:$color} --device=mqtt-device-$deviceId --region=us-central1 --registry=my-registry" > device-send-command-script-$deviceId.sh
 # grants each file execution permission
  chmod u+x device-send-command-script-$deviceId.sh
done
  1. Call all gcloud scripts async to trigger all at once:
#call 3 scripts async
./device-send-command-script-1.sh & ./device-send-command-script-2.sh & ./device-send-command-script-3.sh &

4. Switch back to the tab in which the sample is running

Clean up

When you end the lab all your resources and your project will be cleaned up and discarded for you. You should know how to clean up resources yourself to save on cost and to be a good cloud citizen.

Run the following:

#Removing used script files
for deviceId in 1 2 3
do
  rm ./device-send-command-script-$deviceId.sh
done

The default wait time of the sample is 120 seconds, and the number of messages to be published is 100. You can change this by adding the parameters num_messages and wait_time.

For example:

mvn exec:java \
 -Dexec.mainClass="com.example.cloud.iot.examples.MqttCommandsDemo" \
    -Dexec.args="-project_id=$PROJECT_ID \
                 -registry_id=my-registry \
                 -cloud_region=us-central1 \
                 -device_id=mqtt-device-1 \
                 -private_key_file=rsa_private_pkcs8 \
                 -wait_time=15 \ <desired time in seconds>
                 -num_messages=10 \ <num of event msgs>
                 -algorithm=RS256"

In this lab, you have learned: