如要支援本地執行要求,您必須建構應用程式來處理下列智慧型家居意圖:
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 回報智慧型裝置的狀態。
本機 Home 平台會將相同的要求酬載傳送至「QUERY」處理常式函式,就像傳送至雲端執行服務的 QUERY
意圖一樣。同樣地,您的 QUERY
處理常式會傳回與處理 QUERY
意圖相同格式的資料。
將指令傳送至中樞後方的裝置
如要控制中樞控制器後方的終端裝置,您可能需要在傳送至中樞的特定通訊協定指令酬載中提供額外資訊,讓中樞識別指令要指定哪部裝置。在某些情況下,您可以直接從 device.id
值推斷這項資訊,但如果不是這樣,則應將這項額外資料納入 customData
欄位。
如果您使用 TypeScript 建立應用程式,請務必將應用程式編譯為 JavaScript。您可以使用所選的模組系統編寫程式碼。確認 Chrome 瀏覽器支援目標。