スマートホームをデバッグする

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

1. 始める前に

モノのインターネット(IoT)のデベロッパーは、スマートホーム アクションを作成し、Google Home アプリのタップ操作や Google アシスタントの音声コマンドでユーザーがデバイスを操作できるようにすることができます。

a4657871181b5ad2.gif

スマートホーム アクションのデバッグツールについて学ぶことは、本番環境品質を Google アシスタントと統合するための重要なステップです。Google Cloud Platform(GCP)の指標とロギングスマートホーム向け Test Suite は、アクションの問題を簡単に識別して解決できるよう、モニタリングとデバッグをより簡単に行えるようにします。

前提条件

作成するアプリの概要

この Codelab では、2 つの欠陥を含むスマートホーム アクションをデプロイし、そのアクションをアシスタントに接続します。その後、スマートホーム用テストスイート「Google Cloud Platform(GCP)の指標とロギング」を使用して、そのアクションのデバッグを行います。

学習内容

  • GCP の指標とロギングを使用して本番環境の問題を特定して解決する方法
  • スマートホーム用テストスイートを使用して機能と API の問題を特定する方法

必要なもの

2. 問題のあるアプリを実行する

ソースコードを取得する

下のリンクをクリックして、この Codelab のサンプルを開発マシンにダウンロードします。

または、コマンドラインから GitHub リポジトリのクローンを作成することもできます。

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

プロジェクトについて

洗濯機アプリには、次のサブディレクトリがあります。

  • public: スマート洗濯機の状態を簡単にコントロールしてモニタリングするためのフロントエンド UI。
  • functions: Cloud Functions for FirebaseFirebase Realtime Database を使用してスマート洗濯機を管理する、完全に実装されたクラウド サービス。

Firebase に接続する

開発マシンでターミナルを開きます。washer-faulty ディレクトリに移動し、スマートホーム デバイスを Google アシスタントの Codelab に接続するで作成した Actions プロジェクトを使用して Firebase CLI を設定します。

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

Firebase にデプロイする

functions フォルダに移動し、npm. を使用して必要なすべての依存関係をインストールします。

$ cd functions
$ npm install

注: 下記のメッセージが表示された場合は、無視して続行してください。この警告は、一部の古い依存関係が原因で発生します。詳しくは、こちらをご覧ください。

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

これで、依存関係のインストールとプロジェクトの構成が完了したので、問題のある洗濯アプリをデプロイできるようになりました。

$ firebase deploy

コンソールに次のような出力が表示されます。

...

✔ Deploy complete!

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

HomeGraph の更新

ブラウザでホスティング URLhttps://<project-id>.firebaseapp.com)を開き、ウェブアプリを表示します。ウェブ UI で更新ボタン ae8d3b25777a5e30.png をクリックし、[Request Sync] を介して、故障した洗濯機アプリの最新のデバイス メタデータで HomeGraph を更新します。

6f2b1344179977cf.png

Google Home アプリを開き、洗濯機デバイスが [Faulty Washer] と表示されることを確認します。

e357de6a7faff925.png

3. アクションをテストする

プロジェクトをデプロイしたら、Action によって洗濯機が制御されることを確認します。

洗濯機をテストする

スマートフォンで次の音声コマンドをお試しいただくと、値の変更を確認できます。

「OK Google, 洗濯機をオンにして。」

「OK Google, 洗濯を開始して。」

「OK Google, 洗濯機を一時停止して」

「OK Google, 洗濯を再開して」

「OK Google, 洗濯機を止めて。」

洗濯を一時停止または再開すると、アシスタントは音声で問題があると応答します。

"リーチできませんでした<プロジェクトの表示名>."

この問題をデバッグするには、まずエラーの詳細情報を取得して、根本原因を特定する必要があります。

スマートホームのアナリティクス ダッシュボード

エラーを調べるには、スマートホームのアナリティクス ダッシュボードの使用をおすすめします。ダッシュボードでは、クラウド フルフィルメントの使用状況と健全性の指標を示すグラフが集計されます。

  • [Usage] 指標には、スマートホーム アクションの使用状況の傾向(1 日のアクティブ ユーザー数、フルフィルメントへの合計リクエスト数など)が反映されます。
  • 正常性の指標は、スマートホーム アクションでの異常の発生をモニタリングし、リクエストのレイテンシ、成功率、エラーの内訳を把握するのに役立ちます。

エラーの原因を絞り込むには、以下の手順でプロジェクト ダッシュボードにアクセスします。

  1. Actions Console でプロジェクト ページに移動します。
  2. スマートホーム プロジェクトを選択します。
  3. [Analytics](分析)タブを選択し、[Go to Google Cloud Platform](Google Cloud Platform に移動)をクリックします。

b1735bbe11a7aff8.png

  1. Google Cloud 上のプロジェクトのダッシュボードのリストが表示されます。[Google Home Analytics - Cloud Integration] ダッシュボードを選択します。

5edd3751323176dd.png

  1. [Cloud Fulfillment Errors - Status Breakdown] グラフまで下にスクロールし、ハイライト表示された期間のエラーコードを表示します。

c468743c20a11c15.png

PARTNER_RESPONSE_MISSING_DEVICE エラーコードは、根本原因に関するヒントを提供します。次に、エラーコードに基づいてイベントログを取得し、詳細を確認します。

イベントログにアクセスする

エラーの詳細を確認するには、スマートホーム アクションのイベントログ(Cloud Logging 経由)にアクセスします。

Google Cloud Platform でナビゲーション メニューを開き、[オペレーション] の下の [ロギング] > [ログ エクスプローラ] を選択してプロジェクトのイベントログにアクセスします。検索ボックスで「ログ エクスプローラ」と入力して検索することもできます。

[クエリ] セクションにクエリ PARTNER_RESPONSE_MISSING_DEVICE を入力し、[クエリを実行] をクリックします。クエリに一致するログが [クエリ結果] セクションに表示されます。

747cca0f1249a5a.png

エラーログは、エラーの詳細を含むスマートホーム イベントを示しています。

  • 行われたユーザー アクションは「洗濯を再開しています」です(actionType:"STARTSTOP_UNPAUSE")。これは、最近失敗した音声コマンドに対応します。
  • 関連付けられているデバッグ メッセージは "JSON response does not include device."

デバッグ メッセージに基づいて、洗濯機アプリが EXECUTE レスポンスに正しいデバイスを追加していない理由を確認する必要があります。

エラーの根本原因を特定する

functions/index.js で、各コマンドのステータスと新しいデバイスの状態を返す EXECUTE ハンドラ(onExecute 配列内)を見つけます。EXECUTE レスポンスへのデバイス ID の挿入は、updateDevice 関数の解決によって異なります。

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)));
     }
   }
 }

さらに、updateDevice 関数が洗濯機の一時停止 / 再開を処理する方法を確認します。一時停止 / 再開コマンドと一致する文字列が正しくないことを確認します。

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);
};

エラーを修正する

エラーの根本原因がわかったので、一時停止 / 再開コマンドの文字列を修正できます。

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);
};

修正をテストする

Firebase CLI を使用して、更新したコードをデプロイします。

firebase deploy --only functions

次の音声コマンドを再試行すると、洗濯機の一時停止 / 再開時にアシスタントが正しく応答することがわかります。

「OK Google, 洗濯機を一時停止して。」

=>

"洗濯機を一時停止します。"

「OK Google, 洗濯を再開して」

=>

「承知しました。洗濯を再開します」

質問して、洗濯機の現在の状態をテストすることもできます。

「OK Google, 洗濯機はオンになってる?」

「OK Google, 洗濯機は動いてる?」

「OK Google, 洗濯機の今のステップを教えて」

4. テストスイートを使用してアクションをテストする

手動でテストするだけでなく、自動化されたスマートホーム向けテストスイートを使用して、アクションに関連付けられたデバイスタイプとトレイトに基づいてユースケースを検証することもできます。テストスイートで一連のテストを実行してアクションの問題を検出し、失敗したテストケースの情報を示すメッセージを表示して、イベントログに取り掛かる前にデバッグを迅速化します。

スマートホーム用テストスイートを実行する

スマートホーム アクションをテストスイートごとにテストする手順は次のとおりです。

  1. ウェブブラウザで、スマートホーム用テストスイートを開きます。
  2. 右上のボタンを使用して Google にログインします。これにより、テストスイートから Google アシスタントにコマンドを直接送信できます。
  3. [Project ID] フィールドに、スマートホーム アクションのプロジェクト ID を入力します。[次へ] をクリックして次に進みます。
  4. [Test Settings] ステップで、テストスイートに洗濯機のデバイスタイプとトレイトが一覧表示されます。

78ed6a1ebdb581bf.png

  1. サンプル洗濯機アプリには、洗濯機の追加、削除、名前を変更するための UI がないため、[Test Request Sync] オプションを無効にします。本番環境システムでは、ユーザーがデバイスを追加、削除、名前変更するたびに Request Sync をトリガーする必要があります。
  2. [次へ] をクリックしてテストの実行を開始します。

テストスイートの実行が完了したら、テストケースの結果を確認します。失敗した 2 つのテストケースに、それぞれのエラー メッセージがキャッチされます。

5838d10631c98ed2.png

スマートホーム アクションの失敗をデバッグするには、まずエラー メッセージを分析して、エラーの根本原因を特定する必要があります。

エラー メッセージを分析する

デベロッパーが根本原因を特定できるように、テストスイートでは、失敗したテストケースごとにエラーの理由を示すエラー メッセージが表示されます。

上記の最初の失敗したテストケースの場合、

99e4e5d06965a8a7.png

エラー メッセージは、テストスイートがスマートホーム アクションから報告される州で "isPause": true を想定しているのに、実際の状態には "isPause": false しか含まれていないことを示しています。

さらに、2 番目の失敗したテストケースのエラー メッセージは、スマートホーム アクションからの QUERY レスポンスの状態に "isPause": true が含まれていることを示しています。これは、スマートホーム アクションから報告された状態の "isPause": false とは異なります。

fdb5124102e3a37.png

両方のエラー メッセージから判断して、アクションが isPaused に正しい値を報告しているかどうか確認してください。

エラーの根本原因を特定する

functions/index.js を開きます。この関数は、Report State を使用して状態グラフをホームグラフに送信する reportstate 関数が含まれています。Report State ペイロードを調べると、ペイロードに isPaused 状態がないことがわかります。これは、テストスイートが失敗したテストケースで確認したとおりの状態です。

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,
      });
      ...
    });

エラーを修正する

エラーの根本原因がわかったので、Report State ペイロードに isPaused 状態を追加して functions/index.js を修正します。

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,
              },
            },
          },
        },
      };
      ...
    });

修正をテストする

Firebase CLI を使用して、更新したコードをデプロイします。

$ firebase deploy --only functions

スマートホーム用のテストスイートを再実行すると、すべてのテストケースに合格しています。

148837f85d377dd6.png

5. 完了

17d485868a6771bc.png

これで完了です。スマートホームと GCP のテストスイートを使用して、スマートホーム アクションの問題のトラブルシューティングを行うことができました。

詳細

この Codelab で学んだことを活かして、追加リソースを参照しながら以下の演習に挑戦してみましょう。

アクションの審査(アクションをユーザーに公開するための認定プロセスを含む)を受ける前に行うテストと送信についての詳細もご確認ください。