Carga de archivos desde un dispositivo a la nube con Azure IoT Hub (Java)

Este artículo demuestra cómo las capacidades de carga de archivos de IoT Hub cargan un archivo a Azure blob storage, mediante Java.

En el inicio rápido Enviar telemetría desde un dispositivo a IoT Hub y los artículos de Envío de mensajes de nube a dispositivo con IoT Hub se muestra cómo usar la funcionalidad básica de mensajería del dispositivo a la nube y de la nube al dispositivo de IoT Hub. El tutorial Configuración del enrutamiento de mensajes con IoT Hub muestra una forma de almacenar de manera confiable los mensajes enviados del dispositivo a la nube en Azure Blob Storage. Sin embargo, en algunos casos no es posible asignar fácilmente los datos que los dispositivos envían en los mensajes de dispositivo a nube con un tamaño relativamente reducido que acepta IoT Hub. Por ejemplo:

  • Vídeos
  • Archivos grandes con imágenes
  • Datos de vibración muestreados con alta frecuencia
  • Algún tipo de datos de procesamiento previo.

Dichos archivos se suelen procesar por lotes en la nube mediante herramientas como Azure Data Factory o la pila Hadoop. Cuando necesite cargar archivos desde un dispositivo, todavía puede usar la seguridad y confiabilidad de IoT Hub. Este artículo le muestra cómo. Consulte dos ejemplos de azure-iot-sdk-java en GitHub.

Nota

IoT Hub admite muchas plataformas de dispositivos y lenguajes (p. ej., C, .NET y JavaScript) mediante los SDK de dispositivo IoT de Azure. Consulte el Centro de desarrollo de Azure IoT para saber cómo conectar su dispositivo a Azure IoT Hub.

Importante

La funcionalidad de carga de archivos de los dispositivos que usan la autenticación de la entidad de certificación X.509 está disponible como versión preliminar pública, y se debe habilitar el modo de vista previa. Está disponible con carácter general en dispositivos que usan la autenticación de huella digital X.509 o la atestación de certificado X.509 con el servicio de aprovisionamiento de dispositivos de Azure. Para obtener más información acerca de la autenticación X.509 con IoT Hub, consulte Certificados X.509 compatibles.

Requisitos previos

  • Una instancia de IoT Hub. Cree uno con la CLI o el Azure Portal.

  • Dispositivo registrado. Registre uno en el Azure Portal.

  • Java SE Development Kit 8. Asegúrese de seleccionar Java 8 en Long-term support (Soporte técnico a largo plazo) para obtener descargas de JDK 8.

  • Maven 3

  • El puerto 8883 debería estar abierto en su firewall. En el ejemplo de dispositivo de este artículo se usa el protocolo MQTT, que se comunica mediante el puerto 8883. Este puerto puede estar bloqueado en algunos entornos de red corporativos y educativos. Para más información y para saber cómo solucionar este problema, consulte el artículo sobre la conexión a IoT Hub (MQTT).

Asociación de una cuenta de Azure Storage a IoT Hub

Para cargar archivos desde un dispositivo, debe tener una cuenta de Azure Storage y un contenedor de Azure Blob Storage asociado al centro de IoT. Una vez que asocie la cuenta de almacenamiento y el contenedor con el centro de IoT, este puede proporcionar los elementos de un URI de SAS cuando lo solicite un dispositivo. A continuación, el dispositivo puede usar estos elementos para construir el URI de SAS que usa para autenticarse con Azure Storage y cargar archivos en el contenedor de blobs.

Para asociar una cuenta de Azure Storage con el centro de IoT:

  1. En Configuración del centro, seleccione Carga de archivos en el panel izquierdo del centro de IoT.

    Captura de pantalla que muestra la configuración de carga de archivos seleccionada en el portal.

  2. En el panel Carga de archivos, seleccione Contenedor de Azure Storage. En este artículo, se recomienda que la cuenta de almacenamiento e IoT Hub se encuentren en la misma región.

    • Si ya tiene una cuenta de almacenamiento que desea usar, selecciónela de la lista.

    • Para crear una nueva cuenta de almacenamiento, seleccione + Cuenta de almacenamiento. Proporcione un nombre a la cuenta de almacenamiento y asegúrese de que Ubicación esté establecida en la misma región que el centro de IoT y, a continuación, seleccione Aceptar. La nueva cuenta se crea en el mismo grupo de recursos que el centro de IoT. Cuando se complete la implementación, seleccione la cuenta de almacenamiento de la lista.

    Después de seleccionar la cuenta de almacenamiento, se abre el panel Contenedores.

  3. En el panel Contenedores, seleccione el contenedor de blobs.

    • Si ya tiene un contenedor de blobs que desea usar, selecciónelo en la lista y haga clic en Seleccionar.

    • Para crear un contenedor de blobs, seleccione + Contenedor. Proporcione un nombre para el nuevo contenedor. Para los fines de este artículo, puede dejar todos los demás campos en su valor predeterminado. Seleccione Crear. Cuando finalice la implementación, seleccione el contenedor de la lista y haga clic en Seleccionar.

  4. De nuevo en el panel Carga de archivos, asegúrese de que las notificaciones de archivos estén establecidas en Activadas. Puede dejar el resto de la configuración en sus valores predeterminados. Seleccione Guardar y espere a que se complete la configuración antes de pasar a la siguiente sección.

    Captura de pantalla que muestra la configuración de confirmación de carga de archivos en el portal.

Para obtener instrucciones detalladas sobre cómo crear una cuenta de Azure Storage, consulte Crear una cuenta de almacenamiento. Para obtener instrucciones detalladas sobre cómo asociar una cuenta de almacenamiento y un contenedor de blobs a un centro de IoT, consulte Configuración de cargas de archivos mediante Azure Portal.

Creación de un proyecto mediante Maven

Cree un directorio para el proyecto e inicie un shell en ese directorio. En la línea de comandos, ejecute lo siguiente:

mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

Esto genera un directorio con el mismo nombre que artifactId y una estructura de proyecto estándar:

  my-app
  |-- pom.xml
   -- src
      -- main
         -- java
            -- com
               -- mycompany
                  -- app
                     --App.Java

Con un editor de texto, reemplace el archivo pom.xml por lo siguiente:


<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>my-app</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
      <dependency>
      <groupId>com.microsoft.azure.sdk.iot</groupId>
      <artifactId>iot-device-client</artifactId>
      <version>1.30.1</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.29</version>
    </dependency>    
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.3</version>
            <configuration>
              <source>1.7</source>
              <target>1.7</target>
            </configuration>
        </plugin>
        <plugin>
          <artifactId>maven-shade-plugin</artifactId>
          <version>2.4</version>
          <executions>
              <execution>
                  <phase>package</phase>
                  <goals>
                    <goal>shade</goal>
                  </goals>
                  <configuration>
                      <filters>
                          <filter>
                              <artifact>*:*</artifact>
                              <excludes>
                                  <exclude>META-INF/*.SF</exclude>
                                  <exclude>META-INF/*.RSA</exclude>
                              </excludes>
                          </filter>
                      </filters>
                      <shadedArtifactAttached>true</shadedArtifactAttached>
                      <shadedClassifierName>with-deps</shadedClassifierName>
                  </configuration>
              </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

Carga de un archivo desde una aplicación de dispositivo

Copie el archivo que quiere cargar en la carpeta my-app del árbol del proyecto. Con un editor de texto, reemplace App.java por el código siguiente. Proporcione la cadena de conexión del dispositivo y el nombre de archivo donde corresponda. Ha copiado la cadena de conexión del dispositivo al registrar este.

package com.mycompany.app;

import com.azure.storage.blob.BlobClient;
import com.azure.storage.blob.BlobClientBuilder;
import com.microsoft.azure.sdk.iot.deps.serializer.FileUploadCompletionNotification;
import com.microsoft.azure.sdk.iot.deps.serializer.FileUploadSasUriRequest;
import com.microsoft.azure.sdk.iot.deps.serializer.FileUploadSasUriResponse;
import com.microsoft.azure.sdk.iot.device.DeviceClient;
import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Scanner;

public class App 
{
    /**
     * Upload a single file to blobs using IoT Hub.
     *
     */
    public static void main(String[] args)throws IOException, URISyntaxException
    {
        String connString = "Your device connection string here";
        String fullFileName = "Path of the file to upload";

        System.out.println("Starting...");
        System.out.println("Beginning setup.");

        // File upload will always use HTTPS, DeviceClient will use this protocol only
        //   for the other services like Telemetry, Device Method and Device Twin.
        IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;

        System.out.println("Successfully read input parameters.");

        DeviceClient client = new DeviceClient(connString, protocol);

        System.out.println("Successfully created an IoT Hub client.");

        try
        {
            File file = new File(fullFileName);
            if (file.isDirectory())
            {
                throw new IllegalArgumentException(fullFileName + " is a directory, please provide a single file name, or use the FileUploadSample to upload directories.");
            }

            System.out.println("Retrieving SAS URI from IoT Hub...");
            FileUploadSasUriResponse sasUriResponse = client.getFileUploadSasUri(new FileUploadSasUriRequest(file.getName()));

            System.out.println("Successfully got SAS URI from IoT Hub");
            System.out.println("Correlation Id: " + sasUriResponse.getCorrelationId());
            System.out.println("Container name: " + sasUriResponse.getContainerName());
            System.out.println("Blob name: " + sasUriResponse.getBlobName());
            System.out.println("Blob Uri: " + sasUriResponse.getBlobUri());

            System.out.println("Using the Azure Storage SDK to upload file to Azure Storage...");

            try
            {
                BlobClient blobClient =
                    new BlobClientBuilder()
                        .endpoint(sasUriResponse.getBlobUri().toString())
                        .buildClient();

                blobClient.uploadFromFile(fullFileName);
            }
            catch (Exception e)
            {
                System.out.println("Exception encountered while uploading file to blob: " + e.getMessage());

                System.out.println("Failed to upload file to Azure Storage.");

                System.out.println("Notifying IoT Hub that the SAS URI can be freed and that the file upload failed.");

                // Note that this is done even when the file upload fails. IoT Hub has a fixed number of SAS URIs allowed active
                // at any given time. Once you are done with the file upload, you should free your SAS URI so that other
                // SAS URIs can be generated. If a SAS URI is not freed through this API, then it will free itself eventually
                // based on how long SAS URIs are configured to live on your IoT Hub.
                FileUploadCompletionNotification completionNotification = new FileUploadCompletionNotification(sasUriResponse.getCorrelationId(), false);
                client.completeFileUpload(completionNotification);

                System.out.println("Notified IoT Hub that the SAS URI can be freed and that the file upload was a failure.");

                client.closeNow();
                return;
            }

            System.out.println("Successfully uploaded file to Azure Storage.");

            System.out.println("Notifying IoT Hub that the SAS URI can be freed and that the file upload was a success.");
            FileUploadCompletionNotification completionNotification = new FileUploadCompletionNotification(sasUriResponse.getCorrelationId(), true);
            client.completeFileUpload(completionNotification);
            System.out.println("Successfully notified IoT Hub that the SAS URI can be freed, and that the file upload was a success");
        }
        catch (Exception e)
        {
            System.out.println("On exception, shutting down \n" + " Cause: " + e.getCause() + " \nERROR: " +  e.getMessage());
            System.out.println("Shutting down...");
            client.closeNow();
        }

        System.out.println("Press any key to exit...");

        Scanner scanner = new Scanner(System.in);
        scanner.nextLine();
        System.out.println("Shutting down...");
        client.closeNow();
    }
}

Compilación y ejecución de la aplicación

En la carpeta my-app del símbolo del sistema, ejecute el siguiente comando:

mvn clean package -DskipTests

Una vez finalizada la compilación, ejecute el siguiente comando para ejecutar la aplicación:

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

Puede usar el portal para ver el archivo cargado en el contenedor de almacenamiento que configuró:

Captura de pantalla en la que se muestra un archivo que se ha cargado al contenedor de almacenamiento.

Recepción de una notificación de carga de archivos

En esta sección, se crea una aplicación de consola de Java que recibe mensajes de notificación de carga de archivos de IoT Hub.

  1. Cree un directorio para el proyecto e inicie un shell en ese directorio. En la línea de comandos, ejecute lo siguiente:

    mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
    
  2. En el símbolo del sistema, vaya a la carpeta my-app nueva.

  3. Con un editor de texto, reemplace el archivo pom.xml de la carpeta my-app por lo siguiente. Añadir la dependencia del cliente del servicio le permite usar el paquete iothub-java-service-client en la aplicación para comunicarse con el servicio IoT Hub:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.mycompany.app</groupId>
      <artifactId>my-app</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <name>my-app</name>
      <!-- FIXME change it to the project's website -->
      <url>http://www.example.com</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
      </properties>
    
      <dependencies>
          <dependency>
          <groupId>com.microsoft.azure.sdk.iot</groupId>
          <artifactId>iot-device-client</artifactId>
          <version>1.30.1</version>
        </dependency>
        <dependency>
          <groupId>com.microsoft.azure.sdk.iot</groupId>
          <artifactId>iot-service-client</artifactId>
          <version>1.7.23</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
          <version>1.7.29</version>
        </dependency>    
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    
      <build>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
          <plugins>
            <plugin>
              <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                  <source>1.7</source>
                  <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
              <artifactId>maven-shade-plugin</artifactId>
              <version>2.4</version>
              <executions>
                  <execution>
                      <phase>package</phase>
                      <goals>
                        <goal>shade</goal>
                      </goals>
                      <configuration>
                          <filters>
                              <filter>
                                  <artifact>*:*</artifact>
                                  <excludes>
                                      <exclude>META-INF/*.SF</exclude>
                                      <exclude>META-INF/*.RSA</exclude>
                                  </excludes>
                              </filter>
                          </filters>
                          <shadedArtifactAttached>true</shadedArtifactAttached>
                          <shadedClassifierName>with-deps</shadedClassifierName>
                      </configuration>
                  </execution>
              </executions>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
    

    Nota

    Puede comprobar la versión más reciente de iot-service-client mediante la búsqueda de Maven.

  4. Guarde y cierre el archivo pom.xml.

  5. Obtenga la cadena de conexión del servicio IoT Hub.

    Para obtener la cadena de conexión de IoT Hub para la directiva service, siga estos pasos:

    1. En Azure Portal, seleccione Grupos de recursos. Seleccione el grupo de recursos donde se encuentra el centro y, a continuación, seleccione el centro en la lista de recursos.

    2. En el panel de la izquierda de IoT Hub, seleccione Directivas de acceso compartido.

    3. En la lista de directivas, seleccione la directiva service.

    4. Copie la Cadena de conexión principal y guarde el valor.

    Captura de pantalla que muestra cómo recuperar la cadena de conexión de su IoT Hub en el Azure Portal.

    Para obtener más información sobre las directivas de acceso compartido y los permisos de IoT Hub, consulte Permisos y control del acceso.

  6. Con un editor de texto, abra el archivo my-app\src\main\java\com\mycompany\app\App.java y reemplace el código por lo siguiente.

    package com.mycompany.app;
    
    import com.microsoft.azure.sdk.iot.service.*;
    import java.io.IOException;
    import java.net.URISyntaxException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    
    public class App 
    {
        private static final String connectionString = "{Your service connection string here}";
        private static final IotHubServiceClientProtocol protocol = IotHubServiceClientProtocol.AMQPS;
    
        public static void main(String[] args) throws Exception
        {
            ServiceClient sc = ServiceClient.createFromConnectionString(connectionString, protocol);
    
            FileUploadNotificationReceiver receiver = sc.getFileUploadNotificationReceiver();
            receiver.open();
            FileUploadNotification fileUploadNotification = receiver.receive(2000);
    
            if (fileUploadNotification != null)
            {
                System.out.println("File Upload notification received");
                System.out.println("Device Id : " + fileUploadNotification.getDeviceId());
                System.out.println("Blob Uri: " + fileUploadNotification.getBlobUri());
                System.out.println("Blob Name: " + fileUploadNotification.getBlobName());
                System.out.println("Last Updated : " + fileUploadNotification.getLastUpdatedTimeDate());
                System.out.println("Blob Size (Bytes): " + fileUploadNotification.getBlobSizeInBytes());
                System.out.println("Enqueued Time: " + fileUploadNotification.getEnqueuedTimeUtcDate());
            }
            else
            {
                System.out.println("No file upload notification");
            }
    
            receiver.close();
        }
    
    }
    
  7. Guarda y cierra el archivo my-app\src\main\java\com\mycompany\app\App.java.

  8. Use el siguiente comando para compilar la aplicación y buscar errores:

    mvn clean package -DskipTests
    

Ejecución de la aplicación

Ahora está listo para ejecutar la aplicación.

En la carpeta my-app del símbolo del sistema, ejecute el siguiente comando:

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

En la captura de pantalla siguiente se muestra la salida de la aplicación read-file-upload-notification:

Salida de la aplicación read-file-upload-notification

Pasos siguientes

En este artículo ha aprendido a usar la función de carga de archivos de IoT Hub para simplificar la carga de archivos desde los dispositivos. Puede seguir explorando esta característica con los siguientes artículos:

Para explorar aún más las funcionalidades de IoT Hub, consulte: