ローカル フルフィルメントをサポートするには、次のスマートホーム インテントを処理するアプリを作成する必要があります。
IDENTIFY
: ローカルで制御可能なスマート デバイスの検出をサポートします。インテント ハンドラは、スマート デバイスが検出の際に返したデータを抽出し、レスポンスで Google に送信します。EXECUTE
: コマンドの実行をサポートします。QUERY
: デバイスの状態のクエリをサポートします。REACHABLE_DEVICES
: (省略可)ハブ(またはブリッジ)デバイスにローカル接続され、ローカルで制御可能なエンドデバイスの検出をサポートします。
このアプリは、ユーザーの Google Home または Google Nest デバイスで動作し、スマート デバイスをアシスタントに接続します。アプリは TypeScript(推奨)または JavaScript を使用して作成できます。
TypeScript が推奨されるのは、バインディングを利用して、アプリが返したデータが、プラットフォームが想定するタイプと一致することを静的に保証できるためです。
API の詳細については、Local Home SDK API リファレンスをご覧ください。
次のスニペットで、ローカル フルフィルメント アプリを初期化してハンドラをアタッチする方法を示します。
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onReachableDevices(reachableDevicesHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
プロジェクトを作成する
ローカル フルフィルメント アプリをデプロイするには、コードとそのすべての依存関係向けに JavaScript バンドルをビルドする必要があります。
ローカル フルフィルメント アプリのプロジェクト初期化ツールを使用して、優先のバンドラ構成が含まれる適切なプロジェクト構造をブートストラップします。
プロジェクト テンプレート
バンドラ構成を選択するには、次の例に示すように、npm init
コマンドを実行します。
バンドラ構成が含まれない TypeScript:
npm init @google/local-home-app project-directory/ --bundler none
プロジェクトの構造:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
project-directory は、ローカル フルフィルメント アプリ プロジェクトを格納する新しいディレクトリに置き換えます。
webpack バンドラ構成が含まれる TypeScript:
npm init @google/local-home-app project-directory/ --bundler webpack
プロジェクトの構造:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── webpack.config.web.js ├── webpack.config.node.js └── serve.js
project-directory は、ローカル フルフィルメント アプリ プロジェクトを格納する新しいディレクトリに置き換えます。
rollup バンドラ構成が含まれる TypeScript:
npm init @google/local-home-app project-directory/ --bundler rollup
プロジェクトの構造:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── rollup.config.js └── serve.js
project-directory は、ローカル フルフィルメント アプリ プロジェクトを格納する新しいディレクトリに置き換えます。
Parcel バンドラ構成が含まれる TypeScript:
npm init @google/local-home-app project-directory/ --bundler parcel
プロジェクトの構造:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
project-directory は、ローカル フルフィルメント アプリ プロジェクトを格納する新しいディレクトリに置き換えます。
プロジェクト レベルの共通タスクを実行する
生成されたプロジェクトは、次の npm スクリプトをサポートしています。
cd project-directory/ npm run build
このスクリプトは、TypeScript ソースをコンパイルし、dist/web
サブディレクトリ内の Chrome ランタイム環境の依存関係と、dist/node
サブディレクトリ内の Node.js ランタイム環境の依存関係にアプリをバンドルします。
cd project-directory/ npm run lint npm run compile npm test
このスクリプトは、TypeScript コードの構文を確認し、dist/
サブディレクトリに出力を生成することなくこのコードをコンパイルし、test.ts
から自動テストを実行します。
cd project-directory/ npm run start
開発時には、このスクリプトが Chrome と Node.js のランタイム環境にローカルでアプリ バンドルを提供します。
IDENTIFY ハンドラを実装する
IDENTIFY
ハンドラは、Google Home または Google Nest デバイスが再起動して、未確認のローカル デバイス(ハブに接続されたエンドデバイスを含む)を検出したときにトリガーされます。ローカルホーム プラットフォームは、以前に指定されたスキャン設定情報を使用してローカル デバイスをスキャンし、スキャン結果を使用して IDENTIFY
ハンドラを呼び出します。
ローカルホーム プラットフォームの IdentifyRequest
には、LocalIdentifiedDevice
インスタンスのスキャンデータが含まれています。デバイスを検出したスキャン設定に基づいて作成される device
インスタンスは 1 つのみです。
スキャン結果がデバイスと一致すると、IDENTIFY
ハンドラは IdentifyResponsePayload
オブジェクトを返します。このオブジェクトには、スマートホーム メタデータ(タイプ、トレイト、レポート ステータスなど)と device
オブジェクトが含まれます。
IDENTIFY
レスポンスからの verificationId
が SYNC
レスポンスによって返された otherDeviceIds
の値のいずれかと一致すると、Google でデバイスの関連付けが確立されます。
例
次のスニペットで、スタンドアロン デバイスとハブ統合用の IDENTIFY
ハンドラの作成方法をそれぞれ示します。
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const verificationId = "local-device-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: device.id || "", verificationId, // Must match otherDeviceIds in SYNC response }, }, }; return response; };
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const proxyDeviceId = "local-hub-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: proxyDeviceId, isProxy: true, // Device can control other local devices isLocalOnly: true, // Device not present in `SYNC` response }, }, }; return response; };
ハブに接続されたデバイスを識別する
ハブデバイスを確認すると、そのハブに接続されているエンドデバイスへのコンジットとして処理してから、それらのエンドデバイスの確認を試みます。
ハブデバイスがあることを Google が確認できるようにするには、IDENTIFY
ハンドラに対し次の手順を行います。
SYNC
レスポンスで、ハブに接続されたローカルのエンドデバイスの ID が報告される場合は、IdentifyResponsePayload
でisProxy
をtrue
に設定します。SYNC
レスポンスがハブデバイスを報告しない場合は、IdentifyResponsePayload
のisLocalOnly
をtrue
に設定します。device.id
フィールドには、ハブデバイス自体のローカル デバイス ID が含まれます。
REACHABLE_DEVICES ハンドラを実装する(ハブ統合のみ)
ローカルで制御できるエンドデバイスを確認するため、REACHABLE_DEVICES
インテントが Google から送信されます。Google が検出スキャンを実行するたびに(毎分約 1 回)、ハブがオンラインであることが検出されると、このインテントがトリガーされます。
IDENTIFY
ハンドラと同様に REACHABLE_DEVICES
ハンドラを実装します。ただし、このハンドラでは、ローカル プロキシ(つまりハブ自体)のデバイスがアクセスできる追加のデバイス ID を収集する必要があります。device.verificationId
フィールドには、ハブに接続されているエンドデバイスのローカル デバイス ID が含まれます。
ローカルホーム プラットフォームの ReachableDevicesRequest
には、LocalIdentifiedDevice
のインスタンスが含まれます。このインスタンスを介し、スキャン結果のデータとともに、プロキシ デバイス ID を取得できます。
REACHABLE_DEVICES
ハンドラは ReachableDevicesPayload
オブジェクトを返します。このオブジェクトには、ハブが制御しているエンドデバイスを表す verificationId
値の配列を含む devices
オブジェクトが含まれます。verificationId
値は SYNC
レスポンスからの otherDeviceIds
のいずれかと一致する必要があります。
次のスニペットは、REACHABLE_DEVICES
ハンドラを作成する方法を示しています。
const reachableDevicesHandler = (request: IntentFlow.ReachableDevicesRequest): IntentFlow.ReachableDevicesResponse => { // Reference to the local proxy device const proxyDeviceId = request.inputs[0].payload.device.id; // Gather additional device ids reachable by local proxy device // ... const reachableDevices = [ // Each verificationId must match one of the otherDeviceIds // in the SYNC response { verificationId: "local-device-id-1" }, { verificationId: "local-device-id-2" }, ]; // Return a response const response: IntentFlow.ReachableDevicesResponse = { intent: Intents.REACHABLE_DEVICES, requestId: request.requestId, payload: { devices: reachableDevices, }, }; return response; };
EXECUTE ハンドラを実装する
アプリ内の EXECUTE
ハンドラは、ユーザー コマンドを処理し、Local Home SDK を使用して既存のプロトコルを介してスマート デバイスにアクセスします。
ローカルホーム プラットフォームは、クラウド フルフィルメントへの EXECUTE
インテントと同じ入力ペイロードを EXECUTE
ハンドラ関数に渡します。同様に、EXECUTE
ハンドラは、EXECUTE
インテントの処理と同じ形式で出力データを返します。Local Home SDK が提供する Execute.Response.Builder
クラスを使用すると、レスポンスを簡単に作成できます。
アプリは、デバイスの IP アドレスに直接アクセスできません。代わりに、CommandRequest
インターフェースを使用して、UDP、TCP、HTTP のいずれかのプロトコルに基づいてコマンドを作成します。その後、deviceManager.send()
関数を呼び出してコマンドを送信します。
デバイスにコマンドをターゲティングする場合は、SYNC
レスポンスからのデバイス ID(および含まれる場合は customData
フィールドからのパラメータ)を使用してデバイスと通信します。
例
次のコード スニペットで、EXECUTE
ハンドラの作成方法を示します。
const executeHandler = (request: IntentFlow.ExecuteRequest): Promise<IntentFlow.ExecuteResponse> => { // Extract command(s) and device target(s) from request const command = request.inputs[0].payload.commands[0]; const execution = command.execution[0]; const response = new Execute.Response.Builder() .setRequestId(request.requestId); const result = command.devices.map((device) => { // Target id of the device provided in the SYNC response const deviceId = device.id; // Metadata for the device provided in the SYNC response // Use customData to provide additional required execution parameters const customData: any = device.customData; // Convert execution command into payload for local device let devicePayload: string; // ... // Construct a local device command over TCP const deviceCommand = new DataFlow.TcpRequestData(); deviceCommand.requestId = request.requestId; deviceCommand.deviceId = deviceId; deviceCommand.data = devicePayload; deviceCommand.port = customData.port; deviceCommand.operation = Constants.TcpOperation.WRITE; // Send command to the local device return localHomeApp.getDeviceManager() .send(deviceCommand) .then((result) => { response.setSuccessState(result.deviceId, state); }) .catch((err: IntentFlow.HandlerError) => { err.errorCode = err.errorCode || IntentFlow.ErrorCode.INVALID_REQUEST; response.setErrorState(device.id, err.errorCode); }); }); // Respond once all commands complete return Promise.all(result) .then(() => response.build()); };
QUERY ハンドラを実装する
アプリ内の QUERY
ハンドラは、ユーザー リクエストを処理し、Local Home SDK を使用してスマート デバイスの状態を報告します。
ローカルホーム プラットフォームは、クラウド フルフィルメントへの QUERY
インテントと同じリクエスト ペイロードを QUERY ハンドラ関数に渡します。同様に、QUERY
ハンドラは、QUERY
インテントの処理と同じ形式でデータを返します。
ハブに接続されたデバイスにコマンドを送信する
ハブに接続されたエンドデバイスを制御するには、ハブがコマンド対象のデバイスを識別できるよう、ハブに送信されるプロトコル固有のコマンドのペイロードに、追加情報を提供する必要があります。これは device.id
値から直接推定できる場合もありますが、推定できない場合は、この追加データを customData
フィールドの一部として含める必要があります。
TypeScript を使用してアプリを作成した場合は、必ずアプリを JavaScript にコンパイルしてください。任意のモジュール システムを使用してコードを作成できます。 ターゲットが Chrome ブラウザでサポートされていることをご確認ください。