Envía comandos a dispositivos

Puede usar Cloud IoT Core para enviar comandos a los dispositivos. Los comandos son directivas transitorias y únicas que se envían a los dispositivos conectados a Cloud IoT Core y suscritos al tema de los comandos.

En comparación con las configuraciones del dispositivo, los comandos son más rápidos, se pueden enviar con más frecuencia y son independientes de otras funciones principales de Cloud IoT. Cuando elijas entre comandos y configuraciones, considera si necesitas persistencia o conocimiento a lo largo del tiempo (configuraciones) o prefieres directivas de velocidad o de límite de tiempo (comandos).

Los comandos pueden ser útiles cuando quieres hacer lo siguiente:

  • Enviar mensajes rápidamente a muchos dispositivos en un momento específico
  • Enviar mensajes de gran volumen a muchos dispositivos a la vez
  • Enviar directivas con límite de tiempo que venzan
  • Enviar configuración incremental de dispositivo

Los comandos tienen las siguientes características:

  • Se envían directamente a dispositivos suscritos y conectados
  • No se conservan en Cloud IoT Core
  • Se descartan para dispositivos que no están suscritos y conectados cuando se envía el comando
  • No son únicos (se pueden enviar duplicados, aunque esto es poco probable)
  • No se envían en ningún orden en particular (pero se entregan aproximadamente en el orden de envío)
  • En cualquier formato (BLOB de datos)

Actualmente, Cloud IoT Core solo admite comandos de MQTT (no HTTP).

Comandos en comparación con configuraciones

Cloud IoT Core también admite configuraciones en los dispositivos. Los parámetros de configuración son más coherentes y permanentes que los comandos. Las configuraciones se conservan en Cloud IoT Core y, cuando se usa Dexcom, la configuración más reciente se entrega finalmente a todos los dispositivos suscritos, incluso a los que se suscriben después.

En la siguiente tabla, encontrarás ayuda para decidir si usar un comando o una configuración:

Configuraciones Comandos
Se reintenta la configuración más reciente hasta que se publica (MQTT) Se reintenta para QoS 1, pero no se garantiza que se entregue
Persistente, por lo que si un dispositivo se conecta (MQTT) o sondea (HTTP) más adelante, se seguirá entregando la configuración más reciente No persistente. Se entrega solo a los dispositivos conectados en el momento en que se envía el comando
Cada versión nueva reemplaza a la anterior No hay relación ni orden entre los comandos
Le indica a un dispositivo qué debe "ser"; corresponde al estado en Cloud IoT Core Le indica a un dispositivo qué "hacer" en un momento específico
Mayor latencia Menor latencia
Por lo general, son de tamaño pequeño (máx. 64 KB) Hasta 256 KB
BLOB arbitrario BLOB arbitrario
1 actualización por segundo por dispositivo 1,000 por segundo, por proyecto (configurable)
2,500 por segundo, por registro

Debido a que los comandos no persisten en Cloud IoT Core y no se los vuelve a intentar de forma indefinida, no debes esperar que la telemetría del dispositivo o los datos de estado reflejen un comando en particular. Es posible que el dispositivo no haya recibido el comando o que haya recibido comandos o configuraciones posteriores. Los comandos están diseñados para ser transitorios y no forman parte de los datos del dispositivo a largo plazo.

Para administrar el orden de los comandos y los duplicados, usa la lógica del dispositivo o las aplicaciones cliente.

Cómo enviar un comando

Para enviar un comando a un dispositivo, usa Google Cloud Console, gcloud o la API de Cloud IoT Core.

Console

Para enviar un comando a un dispositivo, haz lo siguiente:

  1. Ve a la página Registros en Google Cloud Console.

    Ir a la página Registros

  2. Haz clic en el ID del registro del dispositivo.
  3. En el menú de registro ubicado a la izquierda, haga clic en Dispositivos.
  4. Haz clic en el ID del dispositivo al que deseas enviar el comando.
  5. En la parte superior de la página, haz clic en Enviar comando.
  6. Selecciona el formato del comando:

    • Texto
    • Base64
  7. En el campo Datos de comandos, ingresa el comando.

  8. En el campo opcional Subfolder, ingresa el nombre de una subcarpeta para este comando. Los dispositivos que están suscritos al tema comodín recibirán comandos enviados a las subcarpetas.

  9. Haz clic en Enviar comando.

gcloud

Para enviar un comando a un dispositivo, ejecuta el comando gcloud iot devices commands send:

gcloud iot devices commands send \
    { --command-file=COMMAND_FILE | --command-data=COMMAND_DATA } \
    --region=REGION  \
    --registry=REGISTRY_ID \
    --device=DEVICE_ID \
    [--subfolder=SUBFOLDER]\

Si los datos del comando contienen caracteres especiales, usa --command-file en lugar de --command-data.

API

Usa el método SendCommandToDevice para enviar un comando.

C#

public static object SendCommand(string deviceId, string projectId,
    string cloudRegion, string registryName, string data)
{
    var cloudIot = CreateAuthorizedClient();

    var devicePath = String.Format("projects/{0}/locations/{1}/registries/{2}/devices/{3}",
        projectId, cloudRegion, registryName, deviceId);
    // Data sent through the wire has to be base64 encoded.
    SendCommandToDeviceRequest req = new SendCommandToDeviceRequest()
    {
        BinaryData = Convert.ToBase64String(Encoding.UTF8.GetBytes(data))
    };

    Console.WriteLine("Sending command to {0}\n", devicePath);

    var res =
        cloudIot.Projects.Locations.Registries.Devices.SendCommandToDevice(req, devicePath).Execute();

    Console.WriteLine("Command response: " + res.ToString());
    return 0;
}

Go


// sendCommand sends a command to a device listening for commands.
func sendCommand(w io.Writer, projectID string, region string, registryID string, deviceID string, sendData string) (*cloudiot.SendCommandToDeviceResponse, error) {
	// Authorize the client using Application Default Credentials.
	// See https://g.co/dv/identity/protocols/application-default-credentials
	ctx := context.Background()
	httpClient, err := google.DefaultClient(ctx, cloudiot.CloudPlatformScope)
	if err != nil {
		return nil, err
	}
	client, err := cloudiot.New(httpClient)
	if err != nil {
		return nil, err
	}

	req := cloudiot.SendCommandToDeviceRequest{
		BinaryData: b64.StdEncoding.EncodeToString([]byte(sendData)),
	}

	name := fmt.Sprintf("projects/%s/locations/%s/registries/%s/devices/%s", projectID, region, registryID, deviceID)

	response, err := client.Projects.Locations.Registries.Devices.SendCommandToDevice(name, &req).Do()
	if err != nil {
		return nil, err
	}

	fmt.Fprintln(w, "Sent command to device")

	return response, nil
}

Java

protected static void sendCommand(
    String deviceId, String projectId, String cloudRegion, String registryName, String data)
    throws GeneralSecurityException, IOException {
  GoogleCredentials credential =
      GoogleCredentials.getApplicationDefault().createScoped(CloudIotScopes.all());
  JsonFactory jsonFactory = JacksonFactory.getDefaultInstance();
  HttpRequestInitializer init = new HttpCredentialsAdapter(credential);
  final CloudIot service =
      new CloudIot.Builder(GoogleNetHttpTransport.newTrustedTransport(), jsonFactory, init)
          .setApplicationName(APP_NAME)
          .build();

  final String devicePath =
      String.format(
          "projects/%s/locations/%s/registries/%s/devices/%s",
          projectId, cloudRegion, registryName, deviceId);

  SendCommandToDeviceRequest req = new SendCommandToDeviceRequest();

  // Data sent through the wire has to be base64 encoded.
  Base64.Encoder encoder = Base64.getEncoder();
  String encPayload = encoder.encodeToString(data.getBytes(StandardCharsets.UTF_8.name()));
  req.setBinaryData(encPayload);
  System.out.printf("Sending command to %s%n", devicePath);

  service
      .projects()
      .locations()
      .registries()
      .devices()
      .sendCommandToDevice(devicePath, req)
      .execute();

  System.out.println("Command response: sent");
}

Node.js

// const cloudRegion = 'us-central1';
// const deviceId = 'my-device';
// const commandMessage = 'message for device';
// const projectId = 'adjective-noun-123';
// const registryId = 'my-registry';
const iot = require('@google-cloud/iot');
const iotClient = new iot.v1.DeviceManagerClient({
  // optional auth parameters.
});

async function sendCommand() {
  // Construct request
  const formattedName = iotClient.devicePath(
    projectId,
    cloudRegion,
    registryId,
    deviceId
  );

  const binaryData = Buffer.from(commandMessage);

  const request = {
    name: formattedName,
    binaryData: binaryData,
  };

  const [response] = await iotClient.sendCommandToDevice(request);
  console.log('Sent command: ', response);
}

sendCommand();

PHP

use Google\Cloud\Iot\V1\DeviceManagerClient;

/**
 * Sends a command to a device.
 *
 * @param string $registryId IOT Device Registry ID
 * @param string $deviceId IOT Device ID
 * @param string $command The command sent to a device
 * @param string $projectId Google Cloud project ID
 * @param string $location (Optional) Google Cloud region
 */
function send_command_to_device(
    $registryId,
    $deviceId,
    $command,
    $projectId,
    $location = 'us-central1'
) {
    print('Sending command to device' . PHP_EOL);

    // Instantiate a client.
    $deviceManager = new DeviceManagerClient();
    $deviceName = $deviceManager->deviceName($projectId, $location, $registryId, $deviceId);

    // Response empty on success
    $deviceManager->sendCommandToDevice($deviceName, $command);

    printf('Command sent' . PHP_EOL);
}

Python

print("Sending command to device")
client = iot_v1.DeviceManagerClient()
device_path = client.device_path(project_id, cloud_region, registry_id, device_id)

# command = 'Hello IoT Core!'
data = command.encode("utf-8")

return client.send_command_to_device(
    request={"name": device_path, "binary_data": data}
)

Ruby

# project_id  = "Your Google Cloud project ID"
# location_id = "The Cloud region the registry is located in"
# registry_id = "The registry containing the device to send commands to"
# device_id   = "The identifier of the device to send commands to"
# data        = "The command, e.g. {move: forward} to send to the device"

require "google/apis/cloudiot_v1"

# Initialize the client and authenticate with the specified scope
Cloudiot   = Google::Apis::CloudiotV1
iot_client = Cloudiot::CloudIotService.new
iot_client.authorization = Google::Auth.get_application_default(
  "https://www.googleapis.com/auth/cloud-platform"
)

# The resource name of the location associated with the project
parent   = "projects/#{project_id}/locations/#{location_id}"
resource = "#{parent}/registries/#{registry_id}/devices/#{device_id}"

command_req = Cloudiot::SendCommandToDeviceRequest.new
command_req.binary_data = data

# Set configuration for the provided device
iot_client.send_project_location_registry_device_command_to_device resource, command_req

puts "Command sent!"

Cómo recibir un comando

Para recibir un comando, el dispositivo debe cumplir con los siguientes requisitos:

  • Estar conectado a Cloud IoT Core con el protocolo MQTT
  • Estar suscrito al tema MQTT /devices/{device-id}/commands/# (el # comodín es obligatorio)

Cuando se suscriba al tema comodín, el dispositivo recibirá comandos enviados a devices/{device-id}/commands, así como comandos enviados a subcarpetas (como devices/{device-id}/commands/{subfolder}). No se admite la suscripción a una subcarpeta específica.

Los comandos se entregan a los dispositivos que están conectados y suscritos en ese momento específico. No se ponen en cola ni se conservan para dispositivos que se conectan y se suscriben más adelante.

Calidad de servicio (QoS)

La entrega de comandos depende del nivel de QoS que uses:

Nivel de QoS Garantía
0 No se garantiza (solo el mejor esfuerzo), incluso cuando la solicitud muestra OK.
1 Entrega al menos una vez garantizada si la solicitud sendCommandtoDevice muestra OK

En otras palabras, en QoS 0, un mensaje se considera correcto en cuanto se envía, sin importar la respuesta del dispositivo. En QoS 1, el éxito significa que el dispositivo confirmó la entrega del mensaje. Ten en cuenta que la entrega "al menos una vez" significa que el dispositivo puede recibir el comando varias veces. Cloud IoT Core no realiza un seguimiento de cuántas veces se recibió el comando.

Errores

  • Si se alcanza el tiempo de espera del comando (60 s, como se indica en Cuotas y límites), se muestra DEADLINE_EXCEEDED.

  • Si el dispositivo no está conectado, o está conectado, pero no está suscrito al tema comodín de MQTT, se muestra FAILED_PRECONDITION.

Logging

Los comandos enviados a dispositivos, así como las confirmaciones de los dispositivos, se registran en Cloud Logging.

Precios

Los comandos se facturan como todos los demás mensajes que se envían mediante MQTT. Para obtener más información, consulta Precios.