Report State

Report State is an important feature which lets the smart home Action proactively report the latest status of the user’s device back to Google’s Home Graph rather than waiting for a QUERY intent.

Report State reports to Google the states of user devices with the specified agentUserId associated with them (sent in the original SYNC request). When the Google Assistant wants to take an action that requires understanding the current state of a device, it can simply look up the state information in the Home Graph instead of issuing a QUERY intent to various third-party clouds prior to issuing the EXECUTE intent.

Without Report State, given lights from multiple providers in a living room, the command Ok Google, brighten my living room requires resolving multiple QUERY intents sent to multiple clouds, as opposed to simply looking up the current brightness values based on what has been previously reported. For the best user experience, the Google Assistant needs to have the current state of a device, without requiring a round-trip to the device.

Home Graph only stores the state that is sent with Report State. The state that is returned as the response to EXECUTE and QUERY intents is used only for speech responses to the user and are not stored in Home Graph. As a result, Report State should be called even if the new state of the device has already been returned in the response to an EXECUTE or QUERY intent. The ReportState API should also be called right after a SYNC intent. After a SYNC intent, new devices might have been added, and in order to set their initial states, a Report State call should follow.

Home Graph expects complete state data on a per-trait basis, as opposed to all state data for the device. For Google Smart Home and Home Graph, traits have state while devices do not. Home Graph updates states on a per-trait basis and overwrites all data for a given trait when a Report State request is sent. For example, if you are reporting state for the StartStop trait, the response needs to include values for both isRunning and isPaused.

If Report State is not implemented, the associated device will not be displayed on visual Assistant surfaces through the QUERY intent. The implementation of Report State is a requirement for the public launch of a Smart Home agent.

Get started

To implement Report State, follow these steps:

Enable the Google HomeGraph API

  1. In the Google Cloud Platform Console, go to the HomeGraph API page.

    Go to the HomeGraph API page
  2. Select the project that matches your smart home project ID.
  3. Click ENABLE.

Create a Service Account Key

Follow these instructions to generate a service account key from the GCP Console:

Note: Ensure that you are using the correct GCP project when performing these steps. This is the project that matches your smart home project ID.
  1. In the GCP Console, go to the Create service account key page.

    Go to the Create Service Account Key page
  2. From the Service account list, select New service account.
  3. In the Service account name field, enter a name.
  4. In the Service account ID field, enter a ID.
  5. From the Role list, select Service Accounts > Service Account Token Creator.

  6. For the Key type, select the JSON option.

  7. Click Create. A JSON file that contains your key downloads to your computer.

Call the API

Select an option from the tabs below:

Node.js

The Actions on Google library for Node.js supports Report State over HTTP.

  1. Place the downloaded service account JSON in your project directory.
  2. Pass the file location into your smarthome constructor
  3. Call the reportState method with your payload. It returns a Promise.
const {smarthome} = require('actions-on-google');
const app = smarthome({
  jwt: mySecretKeyJson
});
// ...
// Device state changed
app.reportState({
  requestId: '123ABC',
  agentUserId: 'user-123',
  payload: {
    devices: {
      states: {
        "light-123": {
          on: true
        }
      }
    }
  }
})
.then((res) => {
  // Report state was successful
})
.catch((res) => {
  // Report state failed
});
    

Java

The Actions on Google library for Java supports Report State over gRPC.

  1. Place the downloaded service account JSON in your project directory.
  2. Read the file location to generate a GoogleCredentials object.
  3. Call the reportState method with your payload. It returns a server response.
private void onDeviceStateUpdated() throws IOException {
    // Get service account key from file
    FileInputStream stream = new FileInputStream("service-account-key.json");
    GoogleCredentials credentials = GoogleCredentials.fromStream(stream);
    mySmartHomeApp.setCredentials(credentials);

    ReportStateAndNotificationResponse response =
        mySmartHomeApp.reportState(ReportStateAndNotificationRequest.newBuilder()
            .setRequestId("123ABC")
            .setAgentUserId("user-123")
            .setPayload(StateAndNotificationPayload.newBuilder()
                .setDevices(ReportStateAndNotificationDevice.newBuilder()
                    .setStates(Struct.newBuilder()
                        .putFields("on", Value.newBuilder().setBoolValue(true).build())
                    )
                    .build()
                )
                .build()
            )
            .build()
        );
}
    

HTTP POST

  1. Use the downloaded service account JSON file to create a JSON Web Token (JWT). For more information, see Authenticating Using a Service Account.
  2. Construct a JWT payload to request an access token with the https://www.googleapis.com/auth/homegraph OAuth scope:
  3. {
      "iss": "<service-account-email>",
      "scope": "https://www.googleapis.com/auth/homegraph",
      "aud": "https://accounts.google.com/o/oauth2/token",
      "iat": <current-time>,
      "exp": <current-time-plus-one-hour>
    }
    
  4. Sign the JWT payload with the private key from your service account.
  5. Use the JWT to request an access token from https://accounts.google.com/o/oauth2/token.
  6. Create the JSON request with the agentUserId. Here's a sample JSON request for Report State:
  7. {
      "requestId": "123ABC",
      "agentUserId": "user-123",
      "payload": {
        "devices": {
          "states": {
            "light-123": {
              "on": true
            }
          }
        }
      }
    }
    
  8. Combine the Report State JSON and the token in your HTTP POST request to the Google Home Graph endpoint. Here's an example of how to make the request in the command line using curl, as a test:
  9. curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" \
      -H "Content-Type: application/json" \
      -d @request-body.json \
      "https://homegraph.googleapis.com/v1/devices:reportStateAndNotification"
    

Handle the Disconnect intent

In the event of unlinking, user data is removed from the Home Graph and Report State calls will fail, resulting in a 404 error. When the user unlinks their account, similar to other intents, Google sends an action.devices.DISCONNECT intent to the fulfillment url.

{
    "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
    "inputs": [{
      "intent": "action.devices.DISCONNECT",
    }]
}

You should handle the DISCONNECT intent if your fulfillment is set to report state back (either through POST or gRPC). If it is not handled, your Action will continue reporting state and will receive an error back every time.

Test Report State

In order to get your action ready for certification, it is important to test report state.

Prerequisites

Before being able to test your action, you need your Service Account Key and your agentUserId. If you already have your Service Account Key and agentUserId, see Deploy the Report State Dashboard.

Deploy the Report State dashboard

Once you have the Service Account Key and agentUserId for your project, download and deploy the latest version from Report State Dashboard. Once you have downloaded the latest version, follow the instructions from the included README.MD file.

After you have deployed the Report State dashboard, access the dashboard from the following URL (replace your_project_id with your project ID):

http://<your-project-id>.appspot.com

On the dashboard, do the following:

  • Choose your Account Key File
  • Add your agentUserId

Then, click List.

All of your devices are listed. Once the list is populated, you can use the Refresh button to update device states. If there is a device state change, the row is highlighted in green.

Error Responses

As you are implementing report state and request sync, there are several possible responses that you will receive from Google. These responses come in the form of HTTP status codes on the response.

  • 200 - Success
  • 400 - Failure: The 400 Bad Request Error is an HTTP response status code that indicates that the server was unable to process the request sent by the client due to invalid syntax. A couple common causes include malformed JSON or using null instead of "" for a string value.
  • 404 - Failure: The requested resource could not be found but may be available in the future. Subsequent requests by the client are permissible. Typically, this means that we cannot find either the user (agentUserId) or the device. It may also mean that the user has not yet linked with Google, or you didn't send the agentUserId in the SYNC response.
  • 429 - Failure: The user has sent too many sync requests in a given amount of time. The limit is simply one concurrent sync request per user at a time. We don't allow for concurrent requests to be made for the same user. This is for request sync only, not for report state. Report state does not have this limitation and will accept concurrent requests for the same device.