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

Cloud-to-cloud 統合のデバッグツールを学習することは、Google アシスタントとの本番環境品質の統合を構築するための重要なステップです。モニタリングとデバッグを容易にするために、Google Cloud Platform(GCP)の指標とロギング、スマートホーム用テストスイートを使用して、統合の問題を特定して解決できます。
前提条件
- Cloud-to-cloud 統合を作成するデベロッパー ガイドを読む
- スマートホーム デバイスを Google アシスタントにリンクする Codelab を実行する
作成するアプリの概要
この Codelab では、2 つの欠陥がある Cloud-to-cloud 統合をデプロイしてアシスタントに接続し、スマートホーム用テストスイートと Google Cloud Platform(GCP)の指標とロギングを使用して統合の欠陥をデバッグします。
学習内容
- GCP の指標とロギングを使用して本番環境の問題を特定して解決する方法
- スマートホーム用テストスイートを使用して機能と API の問題を特定する方法
必要なもの
- ウェブブラウザ(Google Chrome など)
- Google Home アプリがインストールされている iOS または Android デバイス
- Node.js バージョン 24 以降
- 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, 洗濯機を止めて。」
洗濯機を一時停止または再開すると、アシスタントが音声で何らかの問題が発生したことを通知します。
「申し訳ありませんが、<プロジェクトの表示名> に接続できませんでした。」
この問題をデバッグするには、まずエラーの詳細情報を取得して絞り込み、根本原因を特定する必要があります。
Smart Home Analytics ダッシュボード
エラーを検査するのに最適な場所は、Smart Home Analytics ダッシュボードです。このダッシュボードには、クラウド フルフィルメントの使用状況と健全性の指標のグラフが集約されています。
- [使用状況] 指標は、Cloud-to-cloud 統合の使用状況の傾向を反映します。これには、1 日のアクティブ ユーザー数とフルフィルメントへのリクエストの合計数が含まれます。
- [健全性] 指標は、Cloud-to-cloud 統合での異常の発生をモニタリングするのに役立ちます。リクエストのレイテンシ、成功率、エラーの内訳などが含まれます。
エラーの原因を絞り込むには、次の手順に沿ってプロジェクト ダッシュボードにアクセスします。
- デベロッ 1}パー コンソールで、プロジェクト ページに移動します。
- スマートホーム プロジェクトを選択します。
- 左側のメニューで [Analytics] タブをクリックします。

- これにより、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 配列内)を見つけます。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':
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] フィールドに、Cloud-to-cloud 統合のプロジェクト ID を入力します。[次へ] をクリックして続行します。
- [テスト設定] ステップで、テストスイートに洗濯機のデバイスタイプとトレイトが表示されます。

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

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

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

どちらのエラー メッセージにも、統合が状態 isPaused を正しい値で報告しているかどうかを確認する必要があります。
エラーの根本原因を特定する
functions/index.js を開きます。これには、Report State を使用して状態の変更を HomeGraph に送信する 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: 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 の指標とロギングを使用して、Cloud-to-cloud 統合の問題をトラブルシューティングする方法を学習しました。
詳細
この Codelab で学んだことを活かして、追加リソースを参照しながら以下の演習に挑戦してみましょう。
- サポートされているトレイトをデバイスに追加し、テストスイートでテストします。
- ダッシュボードを作成してアラートを設定し、プログラムから指標データにアクセスして、統合に関する有用な使用状況の指標を取得します。
- スマートホームのローカル フルフィルメントについて学習します。
- GitHub のサンプルで詳しいコードを確認する。
統合の審査(統合をユーザーに公開するための認定プロセスを含む)を受ける前に行うテストと送信についての詳細もご確認ください。