1. 始める前に
IoT(モノのインターネット)デベロッパーは、ユーザーが Google Home アプリのタップ コントロールや Google アシスタントへの音声コマンドでデバイスを操作できるクラウド間統合を構築できます。

クラウド間インテグレーションのデバッグツールを学習することは、Google アシスタントとの本番環境品質のインテグレーションを構築するための重要なステップです。モニタリングとデバッグを容易にするため、Google Cloud Platform(GCP)の指標、ロギング、スマートホーム用テストスイートを利用して、統合に関する問題を特定して解決できます。
前提条件
- Cloud-to-cloud 統合を作成するデベロッパー ガイドを読む
- スマートホーム デバイスを Google アシスタントに接続する Codelab を実行する
作成するアプリの概要
この Codelab では、2 つの欠陥を含むクラウド間統合をデプロイしてアシスタントに接続し、スマートホームと Google Cloud Platform(GCP)の指標とロギングのテストスイートを使用して統合の欠陥をデバッグします。
学習内容
- GCP の指標とロギングを使用して本番環境の問題を特定して解決する方法
- スマートホーム用テストスイートを使用して機能と API の問題を特定する方法
必要なもの
- ウェブブラウザ(Google Chrome など)
- Google Home アプリがインストールされている iOS または Android デバイス
- Node.js バージョン 10.16 以降
- Google Cloud 請求先アカウント
2. 問題のあるアプリを実行する
ソースコードを取得する
下のリンクをクリックして、この Codelab のサンプルを開発マシンにダウンロードします。
または、コマンドラインから GitHub リポジトリのクローンを作成することもできます。
$ git clone https://github.com/google-home/smarthome-debug.git
プロジェクトについて
洗濯機アプリには次のサブディレクトリが含まれています。
public: スマート洗濯機の状態を簡単に制御、モニタリングするためのフロントエンド UI。functions: Cloud Functions for Firebase と Firebase Realtime Database を使用してスマート洗濯機を管理する、実装が完了したクラウド サービス
Firebase への接続
開発マシンでターミナルを開きます。washer-faulty ディレクトリに移動し、スマートホーム デバイスを Google アシスタントに接続する Codelab で作成した統合プロジェクトに Firebase CLI を設定します。
$ cd washer-faulty $ firebase use <firebase-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/<Firebase-project-id>/overview Hosting URL: https://<Firebase-project-id>.firebaseapp.com
HomeGraph を更新する
ブラウザで Hosting URL(https://<firebase-project-id>.firebaseapp.com)を開き、ウェブアプリを表示します。ウェブ UI で [Refresh](更新)
ボタンをクリックして、Request Sync を使用して、欠陥のある洗濯機アプリから最新のデバイス メタデータで HomeGraph を更新します。

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

3. 統合をテストする
プロジェクトをデプロイしたら、統合で洗濯機を制御できるかどうかをテストします。
洗濯機をテストする
スマートフォンで以下の音声コマンドを試して、値が変化することを確認します。
「OK Google, 洗濯機をオンにして。」
「OK Google, 洗濯を開始して。」
「OK Google, 洗濯機を一時停止して。」
「OK Google, 洗濯機を再開して。」
「OK Google, 洗濯機を止めて。」
洗濯機を一時停止 / 再開すると、アシスタントが音声でエラーを報告します。
「申し訳ありませんが、<プロジェクトの表示名> にアクセスできませんでした。」
この問題をデバッグするには、まずエラーに関する詳細情報を取得して根本原因を絞り込み、特定する必要があります。
スマートホーム アナリティクス ダッシュボード
エラーを確認するのに最適な場所は、クラウド フルフィルメントの使用状況と健全性に関する指標のグラフを集計した Smarthome Analytics ダッシュボードです。
- [使用状況] 指標には、クラウド間統合の使用状況の傾向(1 日のアクティブ ユーザー数やフルフィルメントへのリクエストの合計数など)が反映されます。
- 健全性指標を使用すると、Cloud-to-Cloud 統合で異常が発生したかどうかをモニタリングできます。リクエスト レイテンシ、成功率、エラーの内訳を確認できます。
エラーの原因を特定するには、次の手順に沿ってプロジェクト ダッシュボードにアクセスします。
- デベロッパー コンソールで、プロジェクト ページに移動します。
- スマートホーム プロジェクトを選択します。
- 左側のメニューで [アナリティクス] タブをクリックします。

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

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

PARTNER_RESPONSE_MISSING_DEVICE エラーコードは、根本原因のヒントになります。次に、エラーコードに基づいてイベントログを取得して、詳細を確認します。
イベントログにアクセスする
エラーの詳細を確認するには、Cloud Logging を使用して Cloud-to-Cloud 統合のイベントログにアクセスします。
Google Cloud Platform で [ナビゲーション メニュー] を開き、[オペレーション] で [ロギング] > [ログ エクスプローラ] を選択して、プロジェクトのイベントログにアクセスします。または、検索ボックスで「ログ エクスプローラ」を検索することもできます。
[すべてのフィールドを検索] 入力フィールドにクエリ PARTNER_RESPONSE_MISSING_DEVICE を入力し、[クエリを実行] をクリックします。クエリに一致するログが [結果] セクションに表示されます。

エラーログには、次のようなエラーの詳細を示すスマートホーム イベントが表示されます。
- ユーザーが実行したアクションは「洗濯機の再開」(
actionType:「STARTSTOP_UNPAUSE」)で、最近失敗した音声コマンドに対応しています。 - 関連するデバッグ メッセージは「
JSON response does not include device.」です。
デバッグ メッセージに基づいて、洗濯機アプリが EXECUTE レスポンスに正しいデバイスを含めていない理由を確認する必要があります。
エラーの根本原因を特定する
functions/index.js で、各コマンドのステータスと更新後のデバイスの状態を返す EXECUTE ハンドラ(onExecute 配列内)を見つけます。デバイス ID を EXECUTE レスポンスに挿入するかどうかは、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':
const data = await queryDevice(deviceId);
state = (data.isPaused === false && data.isRunning === false)
? {isRunning: false, isPaused: false}
: {isRunning: !params.pause, isPaused: params.pause};
ref = getFirebaseRef().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':
const data = await queryDevice(deviceId);
state = (data.isPaused === false && data.isRunning === false)
? {isRunning: false, isPaused: false}
: {isRunning: !params.pause, isPaused: params.pause};
ref = getFirebaseRef().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. テストスイートで統合をテストする
手動でテストできるだけでなく、自動のスマートホーム用テストスイートを使用して、デバイスタイプと、統合に関連付けられたトレイトに基づいてユースケースを検証できます。テストスイートは一連のテストを実行して統合の問題を検出し、失敗したテストケースに関する情報メッセージを表示して、イベントログを調べる前にデバッグを迅速に行えるようにします。
スマートホーム用テストスイートを実行する
テストスイートで Cloud-to-cloud 統合をテストするには、次の手順に沿って操作します。
- ウェブブラウザで、スマートホーム用テストスイートを開きます。
- 右上にあるボタンから Google にログインします。これにより、テストスイートから Google アシスタントに直接コマンドを送信できるようになります。
- [プロジェクト ID] フィールドに、クラウド間統合のプロジェクト ID を入力します。[次へ] をクリックして続行します。
- [Test Settings] ステップで、Test Suite に洗濯機のデバイスタイプとトレイトが表示されます。

- サンプル洗濯機アプリには洗濯機を追加、削除、名前変更する UI がないため、[Test Request Sync](Request Sync のテスト)オプションを無効にします。本番環境システムでは、ユーザーがデバイスを追加、削除、名前変更するたびに Request Sync をトリガーする必要があります。
- [次へ] をクリックして、テストの実行を開始します。
Test Suite の実行が完了したら、テストケースの結果を表示します。次の 2 つのテストケースが失敗し、それぞれのエラー メッセージが表示されます。

クラウド間統合の失敗をデバッグするには、まずエラー メッセージを分析してエラーの根本原因を特定する必要があります。
エラー メッセージを分析する
デベロッパーが根本原因を特定できるように、テストスイートでは、失敗した各テストケースのエラー メッセージに失敗の理由が表示されます。
上記の最初の失敗したテストケースの場合、

エラー メッセージは、テストスイートがクラウド間インテグレーションから報告された状態に "isPause": true を想定しているが、実際の状態には "isPause": false のみが含まれていることを示しています。
また、2 番目の失敗したテストケースのエラー メッセージは、Cloud-to-Cloud 統合からの QUERY レスポンスの状態に "isPause": true が含まれていることを示しています。これは、Cloud-to-Cloud 統合から報告された状態の "isPause": false とは異なります。

どちらのエラー メッセージにも、統合レポートで isPaused が正しい値で報告されているかどうかを確認するよう記載されています。
エラーの根本原因を特定する
functions/index.js を開きます。このファイルには、Report State を使用して状態の変化をホームグラフに投稿する reportstate 関数が含まれています。レポートの状態のペイロードを調べると、ペイロードに 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: snapshot.online,
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: snapshot.online,
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
スマートホーム用テストスイートを再実行すると、すべてのテストケースが合格していることがわかります。

5. 完了

おめでとうございます!スマートホームと GCP の指標とロギングのテストスイートを使用して、クラウド間統合の問題をトラブルシューティングする方法を学習しました。
その他の情報
この Codelab で学んだことを活かして、追加リソースを参照しながら以下の演習に挑戦してみましょう。
- サポートされているトレイトをデバイスに追加し、テストスイートでテストします。
- ダッシュボードを作成し、アラートを設定して、プログラムから指標データにアクセスすることで、インテグレーションに関する有用な使用状況指標を取得できます。
- スマートホームのローカル フルフィルメントを検討する。
- GitHub のサンプルで詳しいコードを確認する。
インテグレーションの審査(インテグレーションをユーザーに公開するための認定プロセスを含む)を受ける前に行うテストと送信についての詳細もご確認ください。