如要支援本機執行要求,您必須建構應用程式來處理這些智慧型住宅意圖:
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 套件。
使用本機出貨應用程式專案初始化器來啟動偏好的專案組合設定,以啟動適當的專案結構。
專案範本
若要選取整合器設定,請執行 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 處理常式
當 Google Home 或 Google Nest 裝置重新啟動,並看到未經驗證的本機裝置 (包括連接至中樞的最終裝置) 時,就會觸發 IDENTIFY
處理常式。本機主畫面平台將使用您先前指定的掃描設定資訊掃描本機裝置,並呼叫 IDENTIFY
處理常式,並提供掃描結果。
本機首頁平台的 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 (即中樞) 裝置可連線的其他裝置 ID。device.verificationId
欄位含有已連線至中樞的最終裝置的本機裝置 ID。
本地首頁平台的 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
處理常式會處理使用者指令,並使用本機通訊協定,透過本機通訊協定存取智慧型裝置。
本機主畫面平台會將輸入酬載傳送至 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
處理常式會處理使用者要求,並使用本機 Home SDK 回報智慧型裝置的狀態。
本機首頁平台會將相同的要求酬載傳送至「QUERY」處理常式函式,就像對雲端執行要求一樣的 QUERY
意圖。同樣地,QUERY
處理常式會傳回與處理 QUERY
意圖相同的格式資料。
將指令傳送至中樞後方的裝置
為控制中心後方的裝置,您可能需要在傳送至 Hub 的通訊協定專屬指令酬載中提供其他資訊,讓中心識別指令的目標裝置。在某些情況下,您可以直接從 device.id
值推論而得,但如果是這種情況,則應在 customData
欄位中加入這項額外資料。
如果您是使用 TypeScript 建立應用程式,請記得將應用程式編譯成 JavaScript。您可以使用您選擇的模組系統來撰寫程式碼。確認您的 Chrome 瀏覽器支援您的目標。