Google Cloud IoT Core is being retired on August 16, 2023. Contact your Google Cloud account team for more information.

Getting device state

With Cloud IoT Core, you can monitor the state of each connected device. State is reported by the device as binary data. Device state updates are typically triggered by a change to the device — either a configuration update from Cloud IoT Core, or a similar change from another external source, such as a firmware update.

Device state differs from device configuration. Configuration data is sent to the device from Cloud IoT Core. State data is sent by the device to Cloud IoT Core. You might think of configuration as an external instruction, and of state as an internal representation.

Cloud IoT Core can help you answer basic questions about configuration and state: What does the device currently "think" it should be doing? How does that compare to the most recent configuration for the device?

Limits

State updates are limited to 1 update per second, per device. However, for best results, device state should be updated much less often — at most, once every 10 seconds.

The update rate is calculated as the time between the most recent server acknowledgment and the next update request.

Reporting device state

MQTT bridge

To report state to Cloud IoT Core through the MQTT bridge, publish messages to the /devices/DEVICE_ID/state MQTT topic. You can select a Cloud Pub/Sub topic to store state events when you create or update a registry.

For more details, see Publishing over the MQTT bridge.

HTTP bridge

To report state to Cloud IoT Core through the HTTP bridge, devices should use a setState request. The binary state data is passed in the body of the request as a base64-encoded string.

For more details, see Publishing over the HTTP bridge.

Getting device state data

This section explains how to get the state data that's reported to Cloud IoT Core by devices. (Devices themselves cannot read state data from the cloud.)

State data is returned in binary format. State data may have a different structure than the configuration data that triggers the state change.

For example, suppose you have a device with several fans. Your configuration data might be a JSON object containing a simple Boolean that enables or disables cooling:

Example of configuration data

{
  'cooling': true
}

But the device's state data might include diagnostic information, as well as the fan data that you'd expect to see in response to a 'cooling' change:

Example of state data

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

The device's firmware_version is not related to the configuration data, but the device returns the full internal representation of its state. This example illustrates how device state can be useful for debugging in general, as well as for confirming that devices have acknowledged specific configurations.

You can get device state data using a Cloud Pub/Sub topic, Cloud Platform Console, the Cloud IoT Core API, or gcloud.

Cloud Pub/Sub Topic

Cloud IoT Core retains state data in storage. You can also configure an optional state notification Cloud Pub/Sub topic in each device registry, via Cloud console, gcloud, or the API. This topic can be the same as or different from the telemetry event topic.

State data is published to Cloud Pub/Sub on a best-effort basis: if publication to the topic fails, it will not be retried. If no topic is defined, device state updates are still persisted internally by Cloud IoT Core, but only the last 10 states are retained.

Console

  1. Go to the Registries page in Google Cloud console.

    Go to the Registries page

  2. Click the ID of the registry for the device.

  3. In the registry menu on the left, click Devices.

  4. Click the ID of the device to go to the Device details page.

  5. Click Configuration & state history. Use the checkboxes to display configuration history, state history, or both. By default, both are shown.

    • A green checkmark indicates that the device has acknowledged the configuration (MQTT only).
    • A yellow warning symbol indicates that the device has not yet acknowledged the configuration (MQTT only).
    • Click a row to get the full configuration or state data in JSON, as well as the timestamp and version.
  6. Click Compare to compare the configuration data with the state data. This view can help you debug configurations and, if you are using MQTT, make sure devices have acknowledged specific configuration versions. (The HTTP bridge does not support acknowledgment of configurations.)

gcloud

To get the most recent state messages for a device (up to 10), run the gcloud iot devices states list command.

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

A state notification Cloud Pub/Sub flag (--state-pubsub-topic) is available for the gcloud iot registries create and update commands:

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 the Device states.list method to get the most recent device states (up to 10). Each Device resource has a DeviceState field that contains the state most recently received from the device. The DeviceRegistry resource has a StateNotificationConfig field that can be used to specify a state notification Cloud Pub/Sub topic when creating or updating a registry.

The following sample shows how to retrieve device state from a device registry:

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 = GsonFactory.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

This sample uses the Google API Client Library for 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