Debugging the Smart Home

1. Before you begin

As an Internet of Things (IoT) developer, you can build smart home Actions that give your users the ability to control their devices through touch controls in the Google Home app and voice commands with the Google Assistant.

79266e5f45e6ae20.gif

Learning the debugging tools for smart home Actions is an important step to build production quality integration with Google Assistant. To facilitate easy monitoring and debugging, Google Cloud Platform (GCP) Metrics and Logging and Test Suite for smart home are available to help you identify and resolve issues for your Actions.

Prerequisites

What you'll build

In this codelab, you'll deploy a smart home Action with 2 defects and connect it to the Assistant, then debug the Action's defects via Test Suite for smart home & Google Cloud Platform (GCP) Metrics and Logging.

What you'll learn

  • How to use GCP Metrics and Logging to identify and resolve production issues
  • How to use Test Suite for smart home to identify functional and API issues

What you'll need

2. Run the faulty app

Get the source code

Click the following link to download the sample for this codelab on your development machine:

Download source code

...or you can clone the GitHub repository from the command line:

$ git clone https://github.com/googlecodelabs/smarthome-debug.git

About the project

The washer app contains the following subdirectories:

Connect to Firebase

Open terminal on your development machine. Navigate to the washer-faulty directory, then set up the Firebase CLI with your Actions project built in the Connect smart home devices to the Google Assistant codelab:

$ cd washer-faulty
$ firebase use <project-id>

Deploy to Firebase

Navigate to the functions folder and install all the necessary dependencies using npm.

$ cd functions
$ npm install

Note: If you see the message below, you can ignore and proceed. The warning is due to some older dependencies and you can find more details here.

found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details

Now that you have installed the dependencies and configured your project, you are ready to deploy the faulty washer app.

$ firebase deploy

This is the console output you should see:

...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/<project-id>/overview
Hosting URL: https://<project-id>.firebaseapp.com

Update HomeGraph

Open the Hosting URL in your browser (https://<project-id>.firebaseapp.com) to view the web app. On the web UI, click the Refresh ae8d3b25777a5e30.png button to update HomeGraph via Request Sync with the latest device metadata from the faulty washer app:

fa3c47f293cfe0b7.png

Open the Google Home app and verify that you can see the washer device named Faulty Washer.

325f9dbdd29e97dd.png

3. Test your Action

After you deploy your project, test that your Action controls the washer.

Test the washer

Check the value change when you try any of the following voice commands through your phone:

"Hey Google, turn on my washer."

"Hey Google, start my washer."

"Hey Google, pause my washer."

"Hey Google, resume my washer."

"Hey Google, stop my washer."

You will notice Assistant responds that something is wrong via voice when you pause / resume the washer:

"Sorry, I couldn't reach <project display name>."

To debug this issue, you first need more information on the error to narrow down and identify the root cause.

Smarthome Analytics dashboard

A good place to inspect errors is Smarthome Analytics dashboard, which aggregates charts of Usage and Health metrics for your cloud fulfillment:

  • The Usage metrics reflects the usage trend of your smart home Action, including the number of daily active users and total request count to your fulfillment.
  • The Health metrics helps you monitor anomaly occurrence on your smart home Action, covering request latency, success percentage, and error breakdown.

To narrow down the error cause, check the error breakdown chart on the dashboard for some clues of the error.

First follow the steps to access dashboard of your project:

  1. In the Actions console, go to the Projects page.
  2. Select your smart home project.
  3. Choose the Analytics tab, and click Go to Google Cloud Platform.

2b8daac10f455583.png

You will see multiple charts including the Smarthome Error Breakdown chart (on the left in the 4th row from the top), which shows number of failed requests breakdown with respective error code:

4a9d87a88b568a63.png

The INVALID_JSON error code provides a hint to the root cause. Next, retrieve event logs based on the error code for more details.

Access event logs

In order to gain more details on the error, access event logs for your smart home Actions via Cloud Logging.

Open the Navigation Menu in Google Cloud Platform. Under Operations, select Logging > Logs Explorer to access Cloud Logging for your project, and run the query INVALID_JSON to retrieve related event logs. You should find the most recent error log:

9bc25c20acf01faa.png

The error log is a smart home event with error details indicating:

  • The user action taken is "resuming washer" (actionType: "STARTSTOP_UNPAUSE"), corresponding to the recent failed voice command.
  • The associated debugging message is "JSON response does not include device."

Based on the debugging message, you should check why the washer app doesn't include the correct device in EXECUTE response.

Identify the root cause of the error

In functions/index.js, find the EXECUTE handler (in the onExecute array) that returns the status of each command and the new device state. The insertion of device IDs into an EXECUTE response depends on the resolving of updateDevice function:

index.js

app.onExecute(async (body) => {
 ...

 for (const command of intent.payload.commands) {
   for (const device of command.devices) {
     for (const execution of command.execution) {
       executePromises.push(
           updateDevice(execution, device.id)
               .then((data) => {
                 result.ids.push(device.id);
                 Object.assign(result.states, data);
               })
               .catch((e) =>
                 functions.logger.error('EXECUTE',
                     device.id, e.message)));
     }
   }
 }

Further check how the updateDevice function handles pause / resume on the washer, and you will find the string to match for the pause / resume command is incorrect:

index.js

const updateDevice = async (execution, deviceId) => {
 const {params, command} = execution;
 let state; let ref;
 switch (command) {
   ...
   case 'action.devices.commands.PauseUnpausePause':
     state = {isPaused: params.pause};
     if (params.pause) state.isRunning = false;
     ref = firebaseRef.child(deviceId).child('StartStop');
     break;
 }

 return ref.update(state)
     .then(() => state);
};

Fix the error

Now that you have identified the root cause of the error, you can correct the string for the pause / resume command:

index.js

const updateDevice = async (execution, deviceId) => {
 const {params, command} = execution;
 let state; let ref;
 switch (command) {
   ...
   case 'action.devices.commands.PauseUnpause':
     state = {isPaused: params.pause};
     if (params.pause) state.isRunning = false;
     ref = firebaseRef.child(deviceId).child('StartStop');
     break;
 }

 return ref.update(state)
     .then(() => state);
};

Test your fix

Deploy the updated code using the Firebase CLI:

firebase deploy --only functions

Retry the following voice commands, and you will find Assistant responds correctly now when you pause / resume the washer.

"Hey Google, pause my washer."

=>

"Sure, pausing the washer."

"Hey Google, resume my washer."

=>

"Got it, resuming the washer."

You can also test the current state of your washer by asking questions.

"Hey Google, is my washer on?"

"Hey Google, is my washer running?"

"Hey Google, what cycle is my washer on?"

4. Test your Action with Test Suite

In addition to testing manually, you can use the automated Test Suite for smart home to validate use cases based on the device types and traits associated with your Action. The Test Suite runs a series of tests to detect issues in your Action, and shows informative messages for failed test cases to expedite your debugging before diving into event logs.

Run Test Suite for smart home

Follow these instructions to test your smart home Action by Test Suite:

  1. In your web browser, open the Test Suite for smart home.
  2. Sign in to Google using the button in the top-right corner. This allows the Test Suite to send the commands directly to Google Assistant.
  3. In the Project ID field, enter the project ID of your smart home Action. And then click NEXT to proceed.
  4. In the Test Settings step, you will see Test Suite list the device type and traits of the washer.

78ed6a1ebdb581bf.png

  1. Disable the Test Request Sync option since the sample washer app has no UI to add / remove / rename the washer. In a production system, you must trigger Request Sync whenever the user adds / removes / renames devices.
  2. Click NEXT to start running the test.

After Test Suite completes running, view the results of test cases. You will notice two failed test cases caught with respective error message:

17cc54782beb9210.png

To debug your smart home Action for the failure, you will need to identify the root cause of the error by first analyzing the error message.

Analyze error message

In order to help developers identify the root cause, Test Suite shows error messages for each failed test case that indicate the reason for the failure.

For the first failed test case above,

605871f220f3ab57.png

its error message indicates Test Suite expects "isPause": true in the states reported from your smart home Action, but the actual states include only "isPause": false.

In addition, the second failed test case's error message indicates the states in QUERY response from your smart home Action include "isPause": true, which differs from "isPause": false in the states reported from your smart home Action:

56fa85437cedc9bc.png

According to both error messages, you should then check whether your Action reports state isPaused with the correct value.

Identify the root cause of the error

Open functions/index.js, which contains the reportstate function that posts state changes to Home Graph via Report State. Inspect the Report State payload, and you will find the payload is missing the isPaused state, which is exactly what the Test Suite checked for in the failed test cases.

index.js

exports.reportstate = functions.database.ref('{deviceId}').onWrite(
    async (change, context) => {
      ...

      const requestBody = {
        requestId: 'ff36a3cc', /* Any unique ID */
        agentUserId: USER_ID,
        payload: {
          devices: {
            states: {
              /* Report the current state of our washer */
              [context.params.deviceId]: {
                online: true,
                on: snapshot.OnOff.on,
                isRunning: snapshot.StartStop.isRunning,
                currentRunCycle: [{
                  currentCycle: 'rinse',
                  nextCycle: 'spin',
                  lang: 'en',
                }],
                currentTotalRemainingTime: 1212,
                currentCycleRemainingTime: 301,
              },
            },
          },
        },
      };

      const res = await homegraph.devices.reportStateAndNotification({
        requestBody,
      });
      ...
    });

Fix the error

Now that you have identified the root cause of the error, revise functions/index.js by adding the isPaused state to the Report State payload:

index.js

exports.reportstate = functions.database.ref('{deviceId}').onWrite(
    async (change, context) => {
      ...

      const requestBody = {
        requestId: 'ff36a3cc', /* Any unique ID */
        agentUserId: USER_ID,
        payload: {
          devices: {
            states: {
              /* Report the current state of our washer */
              [context.params.deviceId]: {
                online: true,
                on: snapshot.OnOff.on,
                isPaused: snapshot.StartStop.isPaused,
                isRunning: snapshot.StartStop.isRunning,
                currentRunCycle: [{
                  currentCycle: 'rinse',
                  nextCycle: 'spin',
                  lang: 'en',
                }],
                currentTotalRemainingTime: 1212,
                currentCycleRemainingTime: 301,
              },
            },
          },
        },
      };
      ...
    });

Test your fix

Deploy the updated code using the Firebase CLI:

$ firebase deploy --only functions

Re-run the Test Suite for smart home, and you will find that all test cases have passed.

322c83f53fbd1366.png

5. Congratulations

674c4f4392e98c1.png

Congratulations! You successfully learned how to troubleshoot smart home Action issues via Test Suite for smart home & GCP Metrics and Logging.

Learn more

Building off this Codelab, try the following exercises and explore additional resources:

You can also learn more about testing and submitting an Action for review, including the certification process to publish your Action to users.