Como acessar o estado do dispositivo

Com o Cloud IoT Core, é possível monitorar o estado de cada dispositivo conectado. O estado é relatado pelo dispositivo como dados binários. As atualizações de estado do dispositivo geralmente são acionadas por uma alteração no dispositivo, seja uma atualização de configuração do Cloud IoT Core ou uma alteração semelhante de outra fonte externa, como uma atualização de firmware.

O estado do dispositivo é diferente da configuração do dispositivo. Os dados de configuração são enviados ao dispositivo a partir do Cloud IoT Core. Os dados de estado são enviados pelo dispositivo para o Cloud IoT Core. Pense na configuração como uma instrução externa e com o estado como uma representação interna.

O Cloud IoT Core pode ajudar você a responder perguntas básicas sobre configuração e estado: o que o dispositivo atualmente "pensa" que ele deveria fazer? Como isso se compara à configuração mais recente do dispositivo?

Limites

As atualizações de estado são limitadas a uma atualização por segundo, por dispositivo. No entanto, para melhores resultados, o estado do dispositivo deve ser atualizado com muito menos frequência, no máximo, uma vez a cada 10 segundos.

A taxa de atualização é calculada como o tempo entre a confirmação mais recente do servidor e a próxima solicitação de atualização.

Relatar o estado do dispositivo

Ponte MQTT

Para informar o estado ao Cloud IoT Core usando a ponte MQTT, publique mensagens no tópico /devices/DEVICE_ID/state do MQTT. Selecione um tópico do Cloud Pub/Sub para armazenar eventos de estado ao criar ou atualizar um registro.

Para mais detalhes, consulte Como publicar pela ponte MQTT.

Ponte HTTP

Para informar o estado ao Cloud IoT Core usando a ponte HTTP, os dispositivos devem usar uma solicitação setState. Os dados de estado binário são transmitidos no corpo da solicitação como uma string codificada em base64.

Para mais detalhes, consulte Como publicar pela ponte HTTP.

Como receber dados de estado do dispositivo

Nesta seção, explicamos como receber os dados de estado que são informados ao Cloud IoT Core por dispositivos. Os dispositivos não podem ler dados de estado da nuvem.

Os dados de estado são retornados no formato binário. Os dados de estado podem ter uma estrutura diferente dos dados de configuração que acionam a mudança de estado.

Por exemplo, suponha que você tenha um dispositivo com diversos fãs. Os dados de configuração podem ser um objeto JSON contendo um booleano simples que ativa ou desativa o resfriamento:

Exemplo de dados de configuração

{
  'cooling': true
}

Mas os dados de estado do dispositivo podem incluir informações de diagnóstico, além dos dados de ventilador que você espera ver em resposta a uma mudança de 'cooling':

Exemplo de dados de estado

{
  'fan1_target_rpm': 1000,
  'fan2_target_rpm': 1200,
  'firmware_version': '1.2.3b'
}

A firmware_version do dispositivo não está relacionada aos dados de configuração, mas o dispositivo retorna a representação interna completa do estado dele. Este exemplo ilustra como o estado do dispositivo pode ser útil para depuração em geral, bem como para confirmar que os dispositivos confirmaram configurações específicas.

É possível receber dados de estado do dispositivo usando um tópico do Cloud Pub/Sub, o Console do Cloud Platform, a API Cloud IoT Core ou o gcloud.

Tópico do Cloud Pub/Sub

O Cloud IoT Core mantém os dados de estado no armazenamento. Também é possível configurar um tópico opcional de notificação de estado do Cloud Pub/Sub em cada registro de dispositivo por meio do Console do Cloud, da gcloud ou da API. Este tópico pode ser igual ou diferente do tópico do evento de telemetria.

Os dados de estado são publicados no Cloud Pub/Sub com base no melhor esforço: se a publicação no tópico falhar, ela não será repetida. Se nenhum tópico for definido, as atualizações de estado do dispositivo serão mantidas internamente pelo Cloud IoT Core, mas somente os últimos 10 estados serão mantidos.

Console

  1. Acesse a página Registros no Console do Cloud.

    Acessar a página Registros

  2. Clique no ID do registro do dispositivo.

  3. No menu de registro à esquerda, clique em Dispositivos.

  4. Clique no código do dispositivo para acessar a página Detalhes do dispositivo.

  5. Clique em Histórico de configuração e de estado. Use as caixas de seleção para exibir o histórico de configuração, o estado ou os dois. Por padrão, ambos são mostrados.

    • Uma marca de seleção verde indica que o dispositivo confirmou a configuração (somente MQTT).
    • Um símbolo de aviso amarelo indica que o dispositivo ainda não reconheceu a configuração (somente MQTT).
    • Clique em uma linha para ver os dados completos de configuração ou estado no JSON, além do carimbo de data/hora e da versão.
  6. Clique em Comparar para comparar os dados de configuração com os dados de estado. Essa visualização pode ajudar você a depurar as configurações. Se você estiver usando MQTT, confirme se os dispositivos confirmaram versões de configuração específicas. A ponte HTTP não é compatível com a confirmação de configurações.

gcloud

Para ver as mensagens de estado mais recentes de um dispositivo (até 10), execute o comando gcloud iot devices states list.

gcloud iot devices states list \
    --registry=REGISTRY_ID \
    --device=DEVICE_ID \
    --region=REGION

Uma sinalização de estado do Cloud Pub/Sub (--state-pubsub-topic) está disponível para os comandos gcloud iot registries create e update:

gcloud iot registries create REGISTRY_ID \
    --project=PROJECT_ID \
    --region=REGION \
    [--event-notification-config=topic=TOPIC,[subfolder=SUBFOLDER] [--event-notification-config=...]]
    [--state-pubsub-topic=STATE_PUBSUB_TOPIC]
gcloud iot registries update REGISTRY_ID \
    --project=PROJECT_ID \
    --region=REGION \
    [--event-notification-config=topic=TOPIC,[subfolder=SUBFOLDER] [--event-notification-config=...]]
    [--state-pubsub-topic=STATE_PUBSUB_TOPIC]

API

Use o método states.list do dispositivo para ver os estados mais recentes deles (até 10). Cada recurso Device tem um campo DeviceState que contém o estado recebido mais recentemente do dispositivo. O recurso DeviceRegistry tem um campo StateNotificationConfig que pode ser usado para especificar um tópico de notificação de estado do Cloud Pub/Sub ao criar ou atualizar um registro.

O exemplo a seguir mostra como recuperar o estado do dispositivo de um registro de dispositivo:

C#

public static object GetDeviceStates(string projectId, string cloudRegion, string registryId, string deviceId)
{
    var cloudIot = CreateAuthorizedClient();

    // The resource name of the location associated with the key rings.
    var name = $"projects/{projectId}/locations/{cloudRegion}/registries/{registryId}/devices/{deviceId}";

    try
    {
        Console.WriteLine("States: ");
        var res = cloudIot.Projects.Locations.Registries.Devices.States.List(name).Execute();
        res.DeviceStates.ToList().ForEach(state =>
        {
            Console.WriteLine($"\t{state.UpdateTime}: {state.BinaryData}");
        });
    }
    catch (Google.GoogleApiException e)
    {
        Console.WriteLine(e.Message);
        if (e.Error != null) return e.Error.Code;
        return -1;
    }
    return 0;
}

Go


// getDeviceStates retrieves and lists device states.
func getDeviceStates(w io.Writer, projectID string, region string, registryID string, device string) ([]*cloudiot.DeviceState, 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
	}

	path := fmt.Sprintf("projects/%s/locations/%s/registries/%s/devices/%s", projectID, region, registryID, device)
	response, err := client.Projects.Locations.Registries.Devices.States.List(path).Do()
	if err != nil {
		return nil, err
	}

	fmt.Fprintln(w, "Successfully retrieved device states!")

	for _, state := range response.DeviceStates {
		fmt.Fprintf(w, "%s : %s\n", state.UpdateTime, state.BinaryData)
	}

	return response.DeviceStates, nil
}

Java

/** Retrieves device metadata from a registry. * */
protected static List<DeviceState> getDeviceStates(
    String deviceId, String projectId, String cloudRegion, String registryName)
    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);

  System.out.println("Retrieving device states " + devicePath);

  ListDeviceStatesResponse resp =
      service.projects().locations().registries().devices().states().list(devicePath).execute();

  return resp.getDeviceStates();
}

Node.js

// const cloudRegion = 'us-central1';
// const deviceId = 'my-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 listDeviceStates() {
  const devicePath = iotClient.devicePath(
    projectId,
    cloudRegion,
    registryId,
    deviceId
  );

  const [response] = await iotClient.listDeviceStates({name: devicePath});
  const states = response.deviceStates;
  if (states.length === 0) {
    console.log(`No States for device: ${deviceId}`);
  } else {
    console.log(`States for device: ${deviceId}`);
  }

  for (let i = 0; i < states.length; i++) {
    const state = states[i];
    console.log(
      'State:',
      state,
      '\nData:\n',
      state.binaryData.toString('utf8')
    );
  }
}

listDeviceStates();

PHP

use Google\Cloud\Iot\V1\DeviceManagerClient;

/**
 * Retrieve a device's state blobs.
 *
 * @param string $registryId IOT Device Registry ID
 * @param string $deviceId IOT Device ID
 * @param string $projectId Google Cloud project ID
 * @param string $location (Optional) Google Cloud region
 */
function get_device_state(
    $registryId,
    $deviceId,
    $projectId,
    $location = 'us-central1'
) {
    print('Getting device state' . PHP_EOL);

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

    $response = $deviceManager->listDeviceStates($deviceName);

    foreach ($response->getDeviceStates() as $state) {
        print('State:' . PHP_EOL);
        printf('    Data: %s' . PHP_EOL, $state->getBinaryData());
        printf('    Update Time: %s' . PHP_EOL,
            $state->getUpdateTime()->toDateTime()->format('Y-m-d H:i:s'));
    }
}

Python

Neste exemplo, usamos a biblioteca de cliente de APIs do Google para Python.
# project_id = 'YOUR_PROJECT_ID'
# cloud_region = 'us-central1'
# registry_id = 'your-registry-id'
# device_id = 'your-device-id'
client = iot_v1.DeviceManagerClient()
device_path = client.device_path(project_id, cloud_region, registry_id, device_id)

device = client.get_device(request={"name": device_path})
print("Last state: {}".format(device.state))

print("State history")
states = client.list_device_states(request={"name": device_path}).device_states
for state in states:
    print("State: {}".format(state))

return states

Ruby

# project_id  = "Your Google Cloud project ID"
# location_id = "The Cloud region the registry is located in"
# registry_id = "The registry to get device states from"
# device_id   = "The identifier of the device to get states for"

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}"

# List the configurations for the provided device
result = iot_client.list_project_location_registry_device_states(
  resource
)
if result.device_states
  result.device_states.each do |state|
    puts "#{state.update_time}: #{state.binary_data}"
  end
else
  puts "No state messages"
end