如要支援本地執行要求,您必須建構應用程式來處理下列智慧型家居意圖:
IDENTIFY
:支援探索本機可控制的智慧型裝置。意圖處理常式會擷取智慧型裝置在探索期間傳回的資料,並在回應中傳送給 Google。EXECUTE
:支援執行指令。QUERY
:支援查詢裝置狀態。REACHABLE_DEVICES
:(選用) 支援在中樞 (或橋接) 裝置後方,搜尋可透過本機控制的終端裝置。
這個應用程式會在使用者的 Google Home 或 Google Nest 裝置上執行,並將智慧型裝置連結至 Google 助理。您可以使用 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 套件。
使用本機執行要求應用程式專案初始化器,以偏好的 Bundler 設定啟動適當的專案結構。
專案範本
如要選取 Bundler 設定,請執行 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 來源,並將應用程式與其依附元件,針對 Chrome 執行階段環境 (位於 dist/web
子目錄) 和 Node.js 執行階段環境 (位於 dist/node
子目錄) 進行封裝。
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 處理常式
當 Google Home 或 Google Nest 裝置重新啟動並偵測到未驗證的本機裝置 (包括連線至中樞的終端裝置) 時,系統會觸發 IDENTIFY
處理常式。Local Home 平台會使用先前指定的掃描設定資訊掃描本機裝置,並以掃描結果呼叫 IDENTIFY
處理常式。
來自 Local Home 平台的 IdentifyRequest
包含 LocalIdentifiedDevice
執行個體的掃描資料。系統會根據偵測到裝置的掃描設定,填入一個 device
例項。
如果掃描結果與裝置相符,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 識別出中樞裝置,會將中樞裝置視為中樞裝置的連線裝置,並嘗試驗證這些終端裝置。
如要讓 Google 確認中樞裝置是否存在,請按照下列操作說明設定 IDENTIFY
處理常式:
- 如果
SYNC
回應回報連線至中樞的本機端裝置 ID,請在IdentifyResponsePayload
中將isProxy
設為true
。 - 如果
SYNC
回應未回報中樞裝置,請在IdentifyResponsePayload
中將isLocalOnly
設為true
。 device.id
欄位包含中樞裝置本身的本機裝置 ID。
實作 REACHABLE_DEVICES 處理常式 (僅限中樞整合)
Google 會傳送 REACHABLE_DEVICES
意圖,確認哪些裝置可在本機控制。只要偵測到中樞裝置已連上網路,這項意圖就會在 Google 執行探索掃描作業 (大約每分鐘一次) 時觸發。
您實作 REACHABLE_DEVICES
處理程序的方式與 IDENTIFY
處理程序類似,但處理程序需要收集本機 Proxy (也就是 Hub) 裝置可存取的其他裝置 ID。device.verificationId
欄位包含已連上集線器的終端裝置的本機裝置 ID。
Local Home 平台的 ReachableDevicesRequest
包含 LocalIdentifiedDevice
的例項。透過這個執行個體,您可以取得 Proxy 裝置 ID 和掃描結果中的資料。
REACHABLE_DEVICES
處理常式應傳回 ReachableDevicesPayload
物件,其中包含 devices
物件,而該物件包含代表中樞控制的終端裝置的 verificationId
值陣列。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 透過現有通訊協定存取智慧型裝置。
本機 Home 平台會將相同的輸入酬載傳遞至 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 回報智慧型裝置的狀態。
Local Home 平台會將與 QUERY
意圖相同的要求酬載傳遞至「QUERY」處理常式函式,傳遞至雲端執行要求。同樣地,您的 QUERY
處理常式會傳回與處理 QUERY
意圖相同格式的資料。
將指令傳送至中樞後方的裝置
如要控制中樞控制器後方的終端裝置,您可能需要在傳送至中樞的特定通訊協定指令酬載中提供額外資訊,讓中樞識別指令要指定哪部裝置。在某些情況下,您可以直接從 device.id
值推斷這項資訊,但如果不是這樣,則應將這項額外資料納入 customData
欄位。
如果您使用 TypeScript 建立應用程式,請務必將應用程式編譯為 JavaScript。您可以使用所選的模組系統編寫程式碼。確認 Chrome 瀏覽器支援目標。