Connect your device to your IoT hub using Java

Introduction

Azure IoT Hub is a fully managed service that enables reliable and secure bi-directional communications between millions of Internet of Things (IoT) devices and a solution back end. One of the biggest challenges that IoT projects face is how to reliably and securely connect devices to the solution back end. To address this challenge, IoT Hub:

  • Offers reliable device-to-cloud and cloud-to-device hyper-scale messaging.
  • Enables secure communications using per-device security credentials and access control.
  • Includes device libraries for the most popular languages and platforms.

This tutorial shows you how to:

  • Use the Azure portal to create an IoT hub.
  • Create a device identity in your IoT hub.
  • Create a simulated device app that sends telemetry to your solution back end.

At the end of this tutorial, you have three Java console apps:

  • create-device-identity, which creates a device identity and associated security key to connect your device app.
  • read-d2c-messages, which displays the telemetry sent by your device app.
  • simulated-device, which connects to your IoT hub with the device identity created earlier, and sends a telemetry message every second using the MQTT protocol.

Note

The article Azure IoT SDKs provides information about the Azure IoT SDKs that you can use to build both apps to run on devices and your solution back end.

To complete this tutorial, you need the following:

Create an IoT hub

Create an IoT hub for your simulated device app to connect to. The following steps show you how to complete this task by using the Azure portal.

  1. Sign in to the Azure portal.
  2. Select New > Internet of Things > IoT Hub.

    Azure portal Jumpbar

  3. In the IoT hub pane, enter the following information for your IoT hub:

    • Name: Create a name for your IoT hub. If the name you enter is valid, a green check mark appears.

    Important

    The IoT hub will be publicly discoverable as a DNS endpoint, so make sure to avoid any sensitive information while naming it.

    • Pricing and scale tier: For this tutorial, select the F1 - Free tier. For more information, see the Pricing and scale tier.

    • Resource group: Create a resource group to host the IoT hub or use an existing one. For more information, see Use resource groups to manage your Azure resources

    • Location: Select the closest location to you.

    • Pin to dashboard: Check this option for easy access to your IoT hub from the dashboard.

      IoT hub window

  4. Click Create. Your IoT hub might take a few minutes to create. You can monitor the progress in the Notifications pane.

Now that you have created an IoT hub, locate the important information that you use to connect devices and applications to your IoT hub.

  1. When the IoT hub has been created successfully, click the new tile for your IoT hub in the Azure portal to open the properties window for the new IoT hub. Make a note of the Hostname, and then click Shared access policies.

    New IoT hub window

  2. In Shared access policies, click the iothubowner policy, and then copy and make note of the IoT Hub connection string in the iothubowner window. For more information, see Access control in the "IoT Hub developer guide."

    Shared access policies

As a final step, make a note of the Primary key value. Then click Endpoints and the Events built-in endpoint. On the Properties blade, make a note of the Event Hub-compatible name and the Event Hub-compatible endpoint address. You need these three values when you create your read-d2c-messages app.

Azure portal IoT Hub Messaging blade

You have now created your IoT hub. You have the IoT Hub host name, IoT Hub connection string, IoT Hub Primary Key, Event Hub-compatible name, and Event Hub-compatible endpoint you need to complete this tutorial.

Create a device identity

In this section, you create a Java console app that creates a device identity in the identity registry in your IoT hub. A device cannot connect to IoT hub unless it has an entry in the identity registry. For more information, see the Identity Registry section of the IoT Hub developer guide. When you run this console app, it generates a unique device ID and key that your device can use to identify itself when it sends device-to-cloud messages to IoT Hub.

  1. Create an empty folder called iot-java-get-started. In the iot-java-get-started folder, create a Maven project called create-device-identity using the following command at your command prompt. Note this is a single, long command:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=create-device-identity -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. At your command prompt, navigate to the create-device-identity folder.

  3. Using a text editor, open the pom.xml file in the create-device-identity folder and add the following dependency to the dependencies node. This dependency enables you to use the iot-service-client package in your app:

    <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-service-client</artifactId>
      <version>1.7.23</version>
    </dependency>
    

    Note

    You can check for the latest version of iot-service-client using Maven search.

  4. Save and close the pom.xml file.

  5. Using a text editor, open the create-device-identity\src\main\java\com\mycompany\app\App.java file.

  6. Add the following import statements to the file:

    import com.microsoft.azure.sdk.iot.service.exceptions.IotHubException;
    import com.microsoft.azure.sdk.iot.service.Device;
    import com.microsoft.azure.sdk.iot.service.RegistryManager;
    
    import java.io.IOException;
    import java.net.URISyntaxException;
    
  7. Add the following class-level variables to the App class, replacing {yourhubconnectionstring} with the value your noted earlier:

    private static final String connectionString = "{yourhubconnectionstring}";
    private static final String deviceId = "myFirstJavaDevice";
    

    Important

    The device ID may be visible in the logs collected for customer support and troubleshooting, so make sure to avoid any sensitive information while naming it.

  8. Modify the signature of the main method to include the exceptions as follows:

    public static void main( String[] args ) throws IOException, URISyntaxException, Exception
    
  9. Add the following code as the body of the main method. This code creates a device called javadevice in your IoT Hub identity registry if doesn't already exist. It then displays the device ID and key that you need later:

    RegistryManager registryManager = RegistryManager.createFromConnectionString(connectionString);
    
    // Create a device that's enabled by default, 
    // with an autogenerated key.
    Device device = Device.createFromId(deviceId, null, null);
    try {
      device = registryManager.addDevice(device);
    } catch (IotHubException iote) {
      // If the device already exists.
      try {
        device = registryManager.getDevice(deviceId);
      } catch (IotHubException iotf) {
        iotf.printStackTrace();
      }
    }
    
    // Display information about the
    // device you created.
    System.out.println("Device Id: " + device.getDeviceId());
    System.out.println("Device key: " + device.getPrimaryKey());
    
  10. Save and close the App.java file.

  11. To build the create-device-identity app using Maven, execute the following command at the command prompt in the create-device-identity folder:

    mvn clean package -DskipTests
    
  12. To run the create-device-identity app using Maven, execute the following command at the command prompt in the create-device-identity folder:

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    
  13. Make a note of the Device ID and Device key. You need these values later when you create an app that connects to IoT Hub as a device.

Note

The IoT Hub identity registry only stores device identities to enable secure access to the IoT hub. It stores device IDs and keys to use as security credentials and an enabled/disabled flag that you can use to disable access for an individual device. If your app needs to store other device-specific metadata, it should use an app-specific store. For more information, see the IoT Hub developer guide.

Receive device-to-cloud messages

In this section, you create a Java console app that reads device-to-cloud messages from IoT Hub. An IoT hub exposes an Event Hub-compatible endpoint to enable you to read device-to-cloud messages. To keep things simple, this tutorial creates a basic reader that is not suitable for a high throughput deployment. The Process device-to-cloud messages tutorial shows you how to process device-to-cloud messages at scale. The Get Started with Event Hubs tutorial provides further information on how to process messages from Event Hubs and is applicable to the IoT Hub Event Hub-compatible endpoints.

Note

The Event Hub-compatible endpoint for reading device-to-cloud messages always uses the AMQP protocol.

  1. In the iot-java-get-started folder you created in the Create a device identity section, create a Maven project called read-d2c-messages using the following command at your command prompt. Note this is a single, long command:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=read-d2c-messages -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. At your command prompt, navigate to the read-d2c-messages folder.

  3. Using a text editor, open the pom.xml file in the read-d2c-messages folder and add the following dependency to the dependencies node. This dependency enables you to use the eventhubs-client package in your app to read from the Event Hub-compatible endpoint:

    <dependency> 
        <groupId>com.microsoft.azure</groupId> 
        <artifactId>azure-eventhubs</artifactId> 
        <version>0.15.0</version> 
    </dependency>
    
  4. Save and close the pom.xml file.

  5. Using a text editor, open the read-d2c-messages\src\main\java\com\mycompany\app\App.java file.

  6. Add the following import statements to the file:

    import java.io.IOException;
    import com.microsoft.azure.eventhubs.*;
    
    import java.nio.charset.Charset;
    import java.time.*;
    import java.util.function.*;
    
  7. Add the following class-level variable to the App class. Replace {youriothubkey}, {youreventhubcompatibleendpoint}, and {youreventhubcompatiblename} with the values you noted previously:

    private static String connStr = "Endpoint={youreventhubcompatibleendpoint};EntityPath={youreventhubcompatiblename};SharedAccessKeyName=iothubowner;SharedAccessKey={youriothubkey}";
    
  8. Add the following receiveMessages method to the App class. This method creates an EventHubClient instance to connect to the Event Hub-compatible endpoint and then asynchronously creates a PartitionReceiver instance to read from an Event Hub partition. It loops continuously and prints the message details until the app terminates.

    // Create a receiver on a partition.
    private static EventHubClient receiveMessages(final String partitionId) {
      EventHubClient client = null;
      try {
        client = EventHubClient.createFromConnectionStringSync(connStr);
      } catch (Exception e) {
        System.out.println("Failed to create client: " + e.getMessage());
        System.exit(1);
      }
      try {
        // Create a receiver using the
        // default Event Hubs consumer group
        // that listens for messages from now on.
        client.createReceiver(EventHubClient.DEFAULT_CONSUMER_GROUP_NAME, partitionId, Instant.now())
          .thenAccept(new Consumer<PartitionReceiver>() {
            public void accept(PartitionReceiver receiver) {
              System.out.println("** Created receiver on partition " + partitionId);
              try {
                while (true) {
                  Iterable<EventData> receivedEvents = receiver.receive(100).get();
                  int batchSize = 0;
                  if (receivedEvents != null) {
                    System.out.println("Got some events");
                    for (EventData receivedEvent : receivedEvents) {
                      System.out.println(String.format("Offset: %s, SeqNo: %s, EnqueueTime: %s",
                        receivedEvent.getSystemProperties().getOffset(),
                        receivedEvent.getSystemProperties().getSequenceNumber(),
                        receivedEvent.getSystemProperties().getEnqueuedTime()));
                      System.out.println(String.format("| Device ID: %s",
                        receivedEvent.getSystemProperties().get("iothub-connection-device-id")));
                      System.out.println(String.format("| Message Payload: %s",
                        new String(receivedEvent.getBytes(), Charset.defaultCharset())));
                      batchSize++;
                    }
                  }
                  System.out.println(String.format("Partition: %s, ReceivedBatch Size: %s", partitionId, batchSize));
                }
              } catch (Exception e) {
                System.out.println("Failed to receive messages: " + e.getMessage());
              }
            }
          });
        } catch (Exception e) {
          System.out.println("Failed to create receiver: " + e.getMessage());
      }
      return client;
    }
    

    Note

    This method uses a filter when it creates the receiver so that the receiver only reads messages sent to IoT Hub after the receiver starts running. This technique is useful in a test environment so you can see the current set of messages. In a production environment, your code should make sure that it processes all the messages - for more information, see the How to process IoT Hub device-to-cloud messages tutorial.

  9. Modify the signature of the main method to include the exception as follows:

    public static void main( String[] args ) throws IOException
    
  10. Add the following code to the main method in the App class. This code creates the two EventHubClient and PartitionReceiver instances and enables you to close the app when you have finished processing messages:

    // Create receivers for partitions 0 and 1.
    EventHubClient client0 = receiveMessages("0");
    EventHubClient client1 = receiveMessages("1");
    System.out.println("Press ENTER to exit.");
    System.in.read();
    try {
      client0.closeSync();
      client1.closeSync();
      System.exit(0);
    } catch (Exception e) {
      System.exit(1);
    }
    

    Note

    This code assumes you created your IoT hub in the F1 (free) tier. A free IoT hub has two partitions named "0" and "1".

  11. Save and close the App.java file.

  12. To build the read-d2c-messages app using Maven, execute the following command at the command prompt in the read-d2c-messages folder:

    mvn clean package -DskipTests
    

Create a device app

In this section, you create a Java console app that simulates a device that sends device-to-cloud messages to an IoT hub.

  1. In the iot-java-get-started folder you created in the Create a device identity section, create a Maven project called simulated-device using the following command at your command prompt. Note this is a single, long command:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=simulated-device -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    
  2. At your command prompt, navigate to the simulated-device folder.

  3. Using a text editor, open the pom.xml file in the simulated-device folder and add the following dependencies to the dependencies node. This dependency enables you to use the iothub-java-client package in your app to communicate with your IoT hub and to serialize Java objects to JSON:

    <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-device-client</artifactId>
      <version>1.3.32</version>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.3.1</version>
    </dependency>
    

    Note

    You can check for the latest version of iot-device-client using Maven search.

  4. Save and close the pom.xml file.

  5. Using a text editor, open the simulated-device\src\main\java\com\mycompany\app\App.java file.

  6. Add the following import statements to the file:

    import com.microsoft.azure.sdk.iot.device.*;
    import com.google.gson.Gson;
    
    import java.io.*;
    import java.net.URISyntaxException;
    import java.util.Random;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ExecutorService;
    
  7. Add the following class-level variables to the App class. Replacing {youriothubname} with your IoT hub name, and {yourdevicekey} with the device key value you generated in the Create a device identity section:

    private static String connString = "HostName={youriothubname}.azure-devices.net;DeviceId=myFirstJavaDevice;SharedAccessKey={yourdevicekey}";
    private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
    private static String deviceId = "myFirstJavaDevice";
    private static DeviceClient client;
    

    This sample app uses the protocol variable when it instantiates a DeviceClient object. You can use either the MQTT, AMQP, or HTTPS protocol to communicate with IoT Hub.

  8. Add the following nested TelemetryDataPoint class inside the App class to specify the telemetry data your device sends to your IoT hub:

    private static class TelemetryDataPoint {
      public String deviceId;
      public double temperature;
      public double humidity;
    
      public String serialize() {
        Gson gson = new Gson();
        return gson.toJson(this);
      }
    }
    
  9. Add the following nested EventCallback class inside the App class to display the acknowledgement status that the IoT hub returns when it processes a message from the device app. This method also notifies the main thread in the app when the message has been processed:

    private static class EventCallback implements IotHubEventCallback {
      public void execute(IotHubStatusCode status, Object context) {
        System.out.println("IoT Hub responded to message with status: " + status.name());
    
        if (context != null) {
          synchronized (context) {
            context.notify();
          }
        }
      }
    }
    
  10. Add the following nested MessageSender class inside the App class. The run method in this class generates sample telemetry data to send to your IoT hub and waits for an acknowledgement before sending the next message:

    private static class MessageSender implements Runnable {
      public void run()  {
        try {
          double minTemperature = 20;
          double minHumidity = 60;
          Random rand = new Random();
    
          while (true) {
            double currentTemperature = minTemperature + rand.nextDouble() * 15;
            double currentHumidity = minHumidity + rand.nextDouble() * 20;
            TelemetryDataPoint telemetryDataPoint = new TelemetryDataPoint();
            telemetryDataPoint.deviceId = deviceId;
            telemetryDataPoint.temperature = currentTemperature;
            telemetryDataPoint.humidity = currentHumidity;
    
            String msgStr = telemetryDataPoint.serialize();
            Message msg = new Message(msgStr);
            msg.setProperty("temperatureAlert", (currentTemperature > 30) ? "true" : "false");
            msg.setMessageId(java.util.UUID.randomUUID().toString()); 
            System.out.println("Sending: " + msgStr);
    
            Object lockobj = new Object();
            EventCallback callback = new EventCallback();
            client.sendEventAsync(msg, callback, lockobj);
    
            synchronized (lockobj) {
              lockobj.wait();
            }
            Thread.sleep(1000);
          }
        } catch (InterruptedException e) {
          System.out.println("Finished.");
        }
      }
    }
    

    This method sends a new device-to-cloud message one second after the IoT hub acknowledges the previous message. The message contains a JSON-serialized object with the deviceId and randomly generated numbers to simulate a temperature sensor, and a humidity sensor.

  11. Replace the main method with the following code that creates a thread to send device-to-cloud messages to your IoT hub:

    public static void main( String[] args ) throws IOException, URISyntaxException {
      client = new DeviceClient(connString, protocol);
      client.open();
    
      MessageSender sender = new MessageSender();
    
      ExecutorService executor = Executors.newFixedThreadPool(1);
      executor.execute(sender);
    
      System.out.println("Press ENTER to exit.");
      System.in.read();
      executor.shutdownNow();
      client.closeNow();
    }
    
  12. Save and close the App.java file.

  13. To build the simulated-device app using Maven, execute the following command at the command prompt in the simulated-device folder:

    mvn clean package -DskipTests
    

Note

To keep things simple, this tutorial does not implement any retry policy. In production code, you should implement retry policies (such as an exponential backoff), as suggested in the MSDN article Transient Fault Handling.

Run the apps

You are now ready to run the apps.

  1. At a command prompt in the read-d2c folder, run the following command to begin monitoring the first partition in your IoT hub:

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App"
    

    Java IoT Hub service app to monitor device-to-cloud messages

  2. At a command prompt in the simulated-device folder, run the following command to begin sending telemetry data to your IoT hub:

    mvn exec:java -Dexec.mainClass="com.mycompany.app.App" 
    

    Java IoT Hub device app to send device-to-cloud messages

  3. The Usage tile in the Azure portal shows the number of messages sent to the IoT hub:

    Azure portal Usage tile showing number of messages sent to IoT Hub

Next steps

In this tutorial, you configured a new IoT hub in the Azure portal, and then created a device identity in the IoT hub's identity registry. You used this device identity to enable the device app to send device-to-cloud messages to the IoT hub. You also created an app that displays the messages received by the IoT hub.

To continue getting started with IoT Hub and to explore other IoT scenarios, see:

To learn how to extend your IoT solution and process device-to-cloud messages at scale, see the Process device-to-cloud messages tutorial.

To continue to get started with Azure IoT Hub and to explore other IoT scenarios, see the following: