Invio di comandi ai dispositivi

Puoi utilizzare Cloud IoT Core per inviare comandi ai dispositivi. I comandi sono istruzioni transitorie una tantum inviate ai dispositivi connessi a Cloud IoT Core e sottoscritti all'argomento dei comandi.

Rispetto alle configurazioni dei dispositivi, i comandi sono più veloci, possono essere inviati più spesso e sono indipendenti dalle altre funzionalità di Cloud IoT Core. Quando scegli tra comandi e configurazioni, valuta se sono necessarie conoscenze e persistenze nel tempo (configurazioni) o preferisci istruzioni relative alla velocità e/o alle limitazioni di tempo (comandi).

I comandi possono essere utili se vuoi:

  • Inviare rapidamente messaggi a molti dispositivi in un momento specifico
  • Inviare messaggi di grandi dimensioni a molti dispositivi in un momento specifico
  • Invia istruzioni vincolate a una scadenza
  • Invia impostazioni incrementali dei dispositivi

I comandi hanno le seguenti caratteristiche:

  • Inviato direttamente ai dispositivi connessi a cui è stato sottoscritto l'abbonamento
  • Non persistenti in Cloud IoT Core
  • Ignorato per i dispositivi che non sono iscritti e connessi al momento dell'invio del comando
  • Non univoco (potrebbero essere inviati duplicati, anche se è improbabile)
  • Non inviato in un ordine particolare (ma consegnato all'incirca nell'ordine di invio)
  • In qualsiasi formato (blob di dati)

Attualmente, Cloud IoT Core supporta solo comandi su MQTT (non HTTP).

Comandi rispetto alle configurazioni

Cloud IoT Core supporta anche le configurazioni dei dispositivi. Le configurazioni sono più coerenti e permanenti rispetto ai comandi. Le configurazioni vengono mantenute in modo permanente in Cloud IoT Core e, quando si utilizza MQTT, l'ultima configurazione viene finalmente fornita a tutti i dispositivi in abbonamento, anche a quelli che hanno un abbonamento successivo.

La tabella seguente può aiutarti a decidere se utilizzare un comando o una configurazione:

Configurazioni Comandi
La configurazione più recente viene ripetuta fino alla pubblicazione (MQTT) È stato eseguito un nuovo tentativo per QoS 1, ma non è garantito che il video venga consegnato
Persistente, quindi se un dispositivo si connette (MQTT) o i sondaggi (HTTP) in un secondo momento, verrà comunque pubblicata la configurazione più recente Non permanente; consegnato solo a dispositivi connessi al momento dell'invio del comando
Ogni nuova versione sostituisce la versione precedente Nessun rapporto o ordine tra i comandi
Indica a un dispositivo l'espressione "be &t";be"; corrisponde a stato in Cloud IoT Core Dice a un dispositivo cosa "fare" in un orario specifico
Maggiore latenza Latenza più bassa
In genere è di dimensioni ridotte (massimo 64 kB). Fino a 256 kB
BLOB arbitrario definito dall'utente BLOB arbitrario definito dall'utente
1 aggiornamento al secondo per dispositivo 1000 al secondo per progetto (configurabile)
2500 al secondo per registro

I comandi non vengono salvati in modo permanente in Cloud IoT Core e non vengono ripetuti, pertanto non devi aspettarti che dati di telemetria o stato del dispositivo riflettano un comando particolare. Il dispositivo potrebbe non aver ricevuto il comando o i comandi o le configurazioni successive. I comandi sono pensati per essere transitori e non fanno parte dei dati a lungo termine relativi ai dispositivi.

Per gestire l'ordinamento dei comandi e i duplicati, utilizza le logiche del dispositivo o le applicazioni client.

Invio di un comando

Per inviare un comando a un dispositivo, utilizza Google Cloud Console, gcloud o l'API Cloud IoT Core.

console

Per inviare un comando a un dispositivo:

  1. Vai alla pagina Registry in Google Cloud Console.

    Vai alla pagina Registry

  2. Fai clic sull'ID del registry del dispositivo.
  3. Nel menu del Registro di sistema a sinistra, fai clic su Dispositivi.
  4. Fai clic sull'ID del dispositivo a cui vuoi inviare il comando.
  5. Nella parte superiore della pagina, fai clic su Invia comando.
  6. Seleziona il formato del comando:

    • Testo
    • Base64
  7. Inserisci il comando nel campo Dati dei comandi.

  8. Nel campo facoltativo Sottocartella, inserisci il nome di una sottocartella per il comando in questione. I dispositivi iscritti all'argomento con caratteri jolly riceveranno i comandi inviati alle sottocartelle.

  9. Fai clic su Invia comando.

gcloud

Per inviare un comando a un dispositivo, esegui il 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]\

Se i dati di comando contengono caratteri speciali, utilizza --command-file invece di --command-data.

API

Utilizza il metodo SendCommandToDevice per inviare 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!"

Ricezione di un comando

Per ricevere un comando, un dispositivo deve:

  • Connettersi a Cloud IoT Core utilizzando il protocollo MQTT
  • Avere sottoscritto l'abbonamento all'argomento MQTT /devices/{device-id}/commands/# (è necessario il carattere jolly)

Se sottoscrivi l'argomento con caratteri jolly, il dispositivo riceverà i comandi inviati a devices/{device-id}/commands e quelli inviati a sottocartelle (ad esempio devices/{device-id}/commands/{subfolder}). La sottoscrizione a una sottocartella specifica non è supportata.

I comandi vengono inviati ai dispositivi connessi e a cui è stato eseguito l'abbonamento in un momento specifico. Non vengono messi in coda o conservati per i dispositivi che si connettono e si abbonano in un secondo momento.

Qualità del servizio (QoS)

La consegna dei comandi dipende dal livello QoS che utilizzi:

Livello QoS Garanzia
0 Non possiamo garantire (solo il massimo sforzo), anche quando la richiesta restituisce OK
1 Consegna "almeno una volta" garantita se la richiesta sendCommandtoDevice restituisce OK

In altre parole, durante lo QoS 0, un messaggio viene considerato riuscito non appena viene inviato, indipendentemente dalla risposta del dispositivo. Nella fase QoS 1, il dispositivo ha confermato l'avvenuta ricezione del messaggio. Tieni presente che la consegna "almeno un'ora" significa che il dispositivo potrebbe ricevere il comando più volte; Cloud IoT Core non tiene traccia del numero di volte in cui il comando è stato ricevuto.

Errori

  • Se viene raggiunto il timeout del comando (60 sec, come indicato in Quote e limiti), viene ripristinato DEADLINE_EXCEEDED.

  • Se il dispositivo non è connesso o non è connesso all'argomento carattere jolly MQTT, FAILED_PRECONDITION viene restituito.

Logging

I comandi inviati ai dispositivi, nonché le conferme dei dispositivi, vengono registrati in Cloud Logging.

Prezzi

I comandi vengono fatturati come tutti gli altri messaggi inviati tramite MQTT. Per i dettagli, consulta la sezione Prezzi.