スマートホームのデバッグ

1. 始める前に

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

a4657871181b5ad2.gif

スマートホーム アクションのデバッグツールを習得することは、本番環境品質の Google アシスタントとの統合を構築するための重要なステップです。簡単にモニタリングとデバッグを行えるよう、Google Cloud Platform(GCP)の指標ロギングスマートホーム用テストスイートを利用できます。これらは、アクションの問題を特定して解決するのに役立ちます。

前提条件

作成するアプリの概要

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

学習内容

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

必要なもの

2. 欠陥のあるアプリを実行する

ソースコードを取得する

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

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

$ git clone https://github.com/google-home/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 を更新する

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

6f2b1344179977cf.png

Google Home アプリを開き、「故障した洗濯機」という名前の洗濯機デバイスが表示されていることを確認します。

e357de6a7faff925.png

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

プロジェクトをデプロイしたら、アクションが洗濯機を制御することをテストします。

洗濯機をテストする

スマートフォンで以下の音声コマンドのいずれかを試して、値の変化を確認します。

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

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

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

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

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

洗濯機を一時停止 / 再開すると、アシスタントが音声で「異常」と応答するようになります。

「<プロジェクトの表示名> にアクセスできませんでした。」

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

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

エラーを調べるのに適した場所は、Smarthome Analytics ダッシュボードです。これは、クラウド フルフィルメントの使用状況と健全性の指標のグラフを集計するものです。

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

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

  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, 洗濯機を一時停止して。」

=&gt;

「はい、洗濯機を一時停止します。」

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

=&gt;

「了解しました。洗濯機を再開します。」

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

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

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

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

4. テストスイートでアクションをテストする

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

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

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

  1. ウェブブラウザで [Test Suite for smart home] を開きます。
  2. 右上のボタンを使用して Google にログインします。これにより、テストスイートはコマンドを Google アシスタントに直接送信できます。
  3. [Project ID](プロジェクト 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 で学んだことを活かして、追加リソースを参照しながら以下の演習に挑戦してみましょう。

また、アクションをユーザーに公開するための認定プロセスなど、アクションのテストと送信の詳細もご確認ください。