1. 事前準備
智慧型住宅整合功能可讓 Google 助理控管使用者的智慧聯網裝置住家如要建立智慧型住宅動作,您必須提供能夠處理智慧型住宅意圖的 Cloud Webhook 端點。例如,使用者說出:「Ok Google,開燈」時Google 助理會將指令傳送至雲端執行要求,藉此更新裝置狀態。
Local Home SDK 可讓您新增本機路徑,將智慧型住宅意圖直接轉送至 Google Home 裝置,藉此強化智慧型住宅的整合作業,進而提升穩定性並減少處理使用者處理作業的延遲時間指令可讓你使用 TypeScript 或 JavaScript 編寫及部署本機執行要求應用程式,藉此識別裝置,並在任何 Google Home 智慧音箱或 Google Nest 智慧螢幕上執行指令。這樣一來,您的應用程式就能直接與使用者現有的標準通訊協定來執行指令。
必要條件
建構項目
在本程式碼研究室中,您將透過 Firebase 部署先前建構的智慧型住宅整合作業,然後在 Actions 主控台中套用掃描設定,並使用 TypeScript 建構本機應用程式,將以 Node.js 編寫的指令傳送到虛擬洗衣機裝置。
課程內容
- 如何在動作主控台中啟用及設定本機執行要求。
- 如何使用 Local Home SDK 編寫本機執行要求應用程式。
- 如何對 Google Home 揚聲器或 Google Nest 智慧螢幕上載入的本機執行要求應用程式進行偵錯。
軟硬體需求
- 最新版 Google Chrome
- 已安裝 Google Home 應用程式的 iOS 或 Android 裝置
- Google Home 智慧音箱或 Google Nest 智慧螢幕
- Node.js 10.16 以上版本
- Google 帳戶
- Google Cloud 帳單帳戶
2. 開始使用
啟用活動控制項
如要使用 Google 助理,你必須將特定活動資料提供給 Google。Google 助理需要這類資料才能正常運作;不過,共用資料的規定並不是 SDK 專用。如要分享這些資料,請建立一個 Google 帳戶 (如果您還沒有帳戶)。您可以使用任何 Google 帳戶,不一定要使用開發人員帳戶。
找到要搭配 Google 助理使用的 Google 帳戶,然後開啟「活動控制項」頁面。
請務必啟用下列切換鈕:
- 網頁與應用程式活動:此外,請務必勾選「包括 Chrome 歷史記錄以及採用 Google 服務的網站、應用程式和裝置中的活動記錄」核取方塊。
- 裝置資訊
- 語音和音訊活動
建立 Actions 專案
- 前往 Actions on Google Developer Console。
- 按一下「新增專案」並輸入專案名稱,然後點選「建立專案」。
選取智慧型住宅應用程式
在 Actions 主控台的總覽畫面中,選取「智慧型住宅」。
選擇「智慧型住宅」體驗資訊卡,即可前往專案控制台。
安裝 Firebase CLI
Firebase 指令列介面 (CLI) 可讓您在本機提供網頁應用程式,並將網頁應用程式部署至 Firebase 託管。
如要安裝 CLI,請從終端機執行下列 npm 指令:
npm install -g firebase-tools
如要確認已正確安裝 CLI,請執行下列指令:
firebase --version
執行下列指令,透過 Google 帳戶授權 Firebase CLI:
firebase login
啟用 HomeGraph API
HomeGraph API 可以在使用者 Home Graph 中儲存和查詢裝置及其狀態。如要使用這個 API,請先開啟 Google Cloud 控制台,並啟用 HomeGraph API。
在 Google Cloud 控制台中,請務必選取與您的動作相符的專案 <project-id>.
,然後在 HomeGraph API 的 API 程式庫畫面中按一下「啟用」。
3. 執行範例應用程式
現在您已設定開發環境,可以部署範例專案,確認所有設定皆正確無誤。
取得原始碼
點選下方連結,即可在開發機器上下載這個程式碼研究室的範例:
...或者從指令列複製 GitHub 存放區:
git clone https://github.com/google-home/smarthome-local.git
關於專案
範例專案包含下列子目錄:
public
:用於控制及監控智慧型洗衣機的前端網頁版 UIfunctions
:為智慧型住宅動作實作雲端執行要求的 Cloud 函式local
:在index.ts
中添加意圖處理常式的本機執行要求應用程式專案架構
提供的 Cloud 執行要求包括下列 index.js
中的函式:
fakeauth
:帳戶連結的授權端點faketoken
:帳戶連結權杖端點smarthome
:智慧型住宅意圖執行要求端點reportstate
:在裝置狀態變更時叫用 HomeGraph APIupdateDevice
:虛擬裝置用來觸發回報狀態的端點
連結至 Firebase
前往 app-start
目錄,然後使用 Actions 專案設定 Firebase CLI:
cd app-start firebase use <project-id>
設定 Firebase 專案
初始化 Firebase 專案。
firebase init
選取 CLI 功能、「即時資料庫」、「函式」,以及包含 Firebase 託管的「託管」功能。
? Which Firebase CLI features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. ❯◉ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance ◯ Firestore: Configure security rules and indexes files for Firestore ◉ Functions: Configure a Cloud Functions directory and its files ◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys ◯ Hosting: Set up GitHub Action deploys ◯ Storage: Configure a security rules file for Cloud Storage ◯ Emulators: Set up local emulators for Firebase products ◯ Remote Config: Configure a template file for Remote Config ◯ Extensions: Set up an empty Extensions manifest
這麼做會為專案初始化必要的 API 和功能。
系統提示時,初始化即時資料庫。您可以使用資料庫執行個體的預設位置。
? It seems like you haven't initialized Realtime Database in your project yet. Do you want to set it up? Yes ? Please choose the location for your default Realtime Database instance: us-central1
您使用的是範例程式碼,因此請選擇安全性規則的預設檔案,而且確保不會覆寫現有的資料庫規則檔案。
? File database.rules.json already exists. Do you want to overwrite it with the Realtime Database Security Rules for <project-ID>-default-rtdb from the Firebase Console? No
如果您要重新初始化專案,請在系統詢問是否要初始化或覆寫程式碼集時,選取「覆寫」。
? Would you like to initialize a new codebase, or overwrite an existing one? Overwrite
設定函式時,請使用預設檔案,並確保您不會覆寫專案範例中現有的 index.js 和 package.json 檔案。
? What language would you like to use to write Cloud Functions? JavaScript ? Do you want to use ESLint to catch probable bugs and enforce style? No ? File functions/package.json already exists. Overwrite? No ? File functions/index.js already exists. Overwrite? No
如果您要重新初始化專案,當系統詢問您要初始化或覆寫函式/.gitignore 時,請選取「No」。
? File functions/.gitignore already exists. Overwrite? No
? Do you want to install dependencies with npm now? Yes
最後,請將「託管」設定設為在專案程式碼中使用 public
目錄,並使用現有的 index.html 檔案。當系統要求使用 ESLint 時,選取「No」。
? What do you want to use as your public directory? public ? Configure as a single-page app (rewrite all urls to /index.html)? Yes ? Set up automatic builds and deploys with GitHub? No ? File public/index.html already exists. Overwrite? No
如果不小心啟用 ESLint,可以透過下列兩種方法停用:
- 使用 GUI,前往專案底下的
../functions
資料夾,選取隱藏的檔案.eslintrc.js
,然後刪除該檔案。請勿將其誤認為名稱相似的.eslintrc.json
。 - 使用指令列:
cd functions rm .eslintrc.js
為確保 Firebase 設定正確且完整,請將 firebase.json
檔案從 washer-done
目錄複製到 washer-start
目錄,並覆寫 washer-start
中的檔案。
在 washer-start
目錄中:
cp -vp ../washer-done/firebase.json .
部署至 Firebase
您已安裝依附元件並設定專案,現在可以開始執行應用程式了。
firebase deploy
以下是控制台輸出內容:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<project-id>/overview Hosting URL: https://<project-id>.web.app
這個指令會部署網頁應用程式和多個 Cloud Functions for Firebase。
在瀏覽器中開啟「Hosting URL」(代管網址) (https://<project-id>.web.app
),即可查看網頁應用程式。您將看到以下介面:
這個網頁版 UI 代表可供查看或修改裝置狀態的第三方平台。如要開始在資料庫中填入裝置資訊,請按一下「更新」。您不會看到任何變更,但會將洗衣機的目前狀態儲存在資料庫中。
現在可以透過動作控制台,將您部署的雲端服務連結至 Google 助理。
設定 Actions 主控台專案
在「總覽」>「簡介」下方建立動作,選取「新增動作」。輸入為智慧型住宅意圖執行要求的 Cloud 函式網址,然後按一下「儲存」。
https://us-central1-<project-id>.cloudfunctions.net/smarthome
在「開發」部分叫用分頁,為動作新增顯示名稱,然後按一下儲存。這個名稱會顯示在 Google Home 應用程式中。
如要啟用帳戶連結,請選取「開發」開發>左側導覽面板中的帳戶連結選項。使用下列帳戶連結設定:
用戶端 ID |
|
用戶端密碼 |
|
驗證網址 |
|
權杖網址 |
|
按一下「儲存」儲存帳戶連結設定,然後按一下「測試」,即可在專案上啟用測試。
系統會將您重新導向至模擬器。將滑鼠遊標移到「裝置測試」() 圖示上,確認專案已啟用測試功能。
連結 Google 助理
如要測試智慧型住宅動作,你必須將專案連結至 Google 帳戶。如此一來,就能透過已登入相同帳戶的 Google 助理介面和 Google Home 應用程式進行測試。
- 在手機上開啟 Google 助理設定。請注意,你登入的帳戶必須與控制台中使用的帳戶相同。
- 瀏覽至 Google 助理 >設定 >居家控制系統 (位於 Google 助理下方)。
- 按一下右上方的搜尋圖示。
- 使用 [test] 前置字串搜尋您的測試應用程式,
- 選取該項目。接著,Google 助理會使用您的服務進行驗證並傳送
SYNC
要求,要求您的服務為使用者提供裝置清單。
開啟 Google Home 應用程式,並確認可以看見洗衣機。
確認你可以在 Google Home 應用程式中使用語音指令控制洗衣機。您也應該會在雲端執行要求的前端網路 UI 中看到裝置狀態變更。
您現在可以開始在動作中新增本地執行要求。
4. 更新 Cloud 執行要求
如要支援本機執行要求,您必須在 Cloud SYNC
回應中新增名為 otherDeviceIds
的個別裝置欄位,其中包含裝置專屬本機 ID。這個欄位也表示使用者能在本機控制該裝置。
將 otherDeviceIds
欄位新增至 SYNC
回應,如以下程式碼片段所示:
functions/index.js
app.onSync((body) => {
return {
requestId: body.requestId,
payload: {
agentUserId: '123',
devices: [{
id: 'washer',
type: 'action.devices.types.WASHER',
traits: [ ... ],
name: { ... },
deviceInfo: { ... },
willReportState: true,
attributes: {
pausable: true,
},
otherDeviceIds: [{
deviceId: 'deviceid123',
}],
}],
},
};
});
將更新後的專案部署至 Firebase:
firebase deploy --only functions
部署完成後,前往網頁版 UI,然後按一下工具列中的「重新整理」 按鈕 。這會觸發要求同步處理作業,以便 Google 助理接收更新後的 SYNC
回應資料。
5. 設定本地執行要求
在本節中,您將為智慧型住宅動作新增必要的本機執行要求設定選項。在開發期間,您需要將本機執行要求應用程式發布至 Firebase 代管,以便 Google Home 裝置存取及下載該應用程式。
在 Actions 主控台中,選取「Develop」(開發) >「動作」,然後找到「設定本機主畫面 SDK」部分。在測試網址欄位中輸入下列網址,插入專案 ID,然後按一下「儲存」:
https://<project-id>.web.app/local-home/index.html
接下來,請定義 Google Home 裝置要如何探索當地智慧型裝置。Local Home 平台支援多種通訊協定來探索裝置,包括 mDNS、UPnP 和 UDP 廣播。您將使用 UDP 廣播來探索智慧型洗衣機。
按一下「裝置掃描設定」底下的「新增掃描設定」,加入新的掃描設定。通訊協定選取「UDP」,然後填寫下列屬性:
欄位 | 說明 | 建議值 |
廣播位址 | UDP 廣播位址 |
|
廣播通訊埠 | Google Home 傳送 UDP 廣播的通訊埠 |
|
監聽通訊埠 | Google Home 會監聽回應的通訊埠 |
|
探索封包 | UDP 廣播資料酬載 |
|
最後,按一下視窗頂端的「儲存」即可發布變更。
6. 實作本地執行要求
您將使用 Local Home SDK 型錄套件,以 TypeScript 開發本地執行要求應用程式。請查看範例專案提供的架構:
local/index.ts
/// <reference types="@google/local-home-sdk" />
import App = smarthome.App;
import Constants = smarthome.Constants;
import DataFlow = smarthome.DataFlow;
import Execute = smarthome.Execute;
import Intents = smarthome.Intents;
import IntentFlow = smarthome.IntentFlow;
...
class LocalExecutionApp {
constructor(private readonly app: App) { }
identifyHandler(request: IntentFlow.IdentifyRequest):
Promise<IntentFlow.IdentifyResponse> {
// TODO: Implement device identification
}
executeHandler(request: IntentFlow.ExecuteRequest):
Promise<IntentFlow.ExecuteResponse> {
// TODO: Implement local fulfillment
}
...
}
const localHomeSdk = new App('1.0.0');
const localApp = new LocalExecutionApp(localHomeSdk);
localHomeSdk
.onIdentify(localApp.identifyHandler.bind(localApp))
.onExecute(localApp.executeHandler.bind(localApp))
.listen()
.then(() => console.log('Ready'))
.catch((e: Error) => console.error(e));
本機執行要求的核心元件是 smarthome.App
類別。範例專案會為 IDENTIFY
和 EXECUTE
意圖附加處理常式,然後呼叫 listen()
方法,通知 Local Home SDK 應用程式已準備就緒。
新增 IDENTIFY 處理常式
當 Google Home 裝置根據 Actions 主控台提供的掃描設定,在區域網路上發現未經驗證的裝置時,Local Home SDK 會觸發 IDENTIFY
處理常式。
同時,當 Google 發現相符的裝置時,平台會使用產生的掃描資料叫用 identifyHandler
。在應用程式中,系統會使用 UDP 廣播進行掃描,而提供給 IDENTIFY
處理常式的掃描資料會包含本機裝置傳送的回應酬載。
處理常式會傳回包含本機裝置專屬 ID 的 IdentifyResponse
執行個體。將下列程式碼新增至 identifyHandler
方法中,以便處理本機裝置傳送的 UDP 回應,並判斷適當的本機裝置 ID:
local/index .ts
identifyHandler(request: IntentFlow.IdentifyRequest):
Promise<IntentFlow.IdentifyResponse> {
console.log("IDENTIFY intent: " + JSON.stringify(request, null, 2));
const scanData = request.inputs[0].payload.device.udpScanData;
if (!scanData) {
const err = new IntentFlow.HandlerError(request.requestId,
'invalid_request', 'Invalid scan data');
return Promise.reject(err);
}
// In this codelab, the scan data contains only local device id.
const localDeviceId = Buffer.from(scanData.data, 'hex');
const response: IntentFlow.IdentifyResponse = {
intent: Intents.IDENTIFY,
requestId: request.requestId,
payload: {
device: {
id: 'washer',
verificationId: localDeviceId.toString(),
}
}
};
console.log("IDENTIFY response: " + JSON.stringify(response, null, 2));
return Promise.resolve(response);
}
請注意,verificationId
欄位必須與 SYNC
回應中的其中一個 otherDeviceIds
值相符,這樣就能在使用者的「Home Graph」中標示裝置是否可用於本機執行要求。如果 Google 找到相符裝置,系統就會將該裝置視為已驗證,並準備好在本地出貨。
新增 EXECUTE 處理常式
Local Home SDK 會在支援本機執行要求的裝置收到指令時,觸發 EXECUTE
處理常式。本機意圖的內容等同於傳送至雲端執行要求的 EXECUTE
意圖,因此在本機處理意圖的邏輯會與您在雲端處理意圖的方式類似。
應用程式可以使用 TCP/UDP 通訊端或 HTTP(S) 要求與本機裝置通訊。在本程式碼研究室中,HTTP 是用來控制虛擬裝置的通訊協定。在 index.ts
中,通訊埠號碼定義為 SERVER_PORT
變數。
將下列程式碼新增至 executeHandler
方法,以便處理傳入的指令,並透過 HTTP 傳送到本機裝置:
local/index.ts
executeHandler(request: IntentFlow.ExecuteRequest):
Promise<IntentFlow.ExecuteResponse> {
console.log("EXECUTE intent: " + JSON.stringify(request, null, 2));
const command = request.inputs[0].payload.commands[0];
const execution = command.execution[0];
const response = new Execute.Response.Builder()
.setRequestId(request.requestId);
const promises: Array<Promise<void>> = command.devices.map((device) => {
console.log("Handling EXECUTE intent for device: " + JSON.stringify(device));
// Convert execution params to a string for the local device
const params = execution.params as IWasherParams;
const payload = this.getDataForCommand(execution.command, params);
// Create a command to send over the local network
const radioCommand = new DataFlow.HttpRequestData();
radioCommand.requestId = request.requestId;
radioCommand.deviceId = device.id;
radioCommand.data = JSON.stringify(payload);
radioCommand.dataType = 'application/json';
radioCommand.port = SERVER_PORT;
radioCommand.method = Constants.HttpOperation.POST;
radioCommand.isSecure = false;
console.log("Sending request to the smart home device:", payload);
return this.app.getDeviceManager()
.send(radioCommand)
.then(() => {
const state = {online: true};
response.setSuccessState(device.id, Object.assign(state, params));
console.log(`Command successfully sent to ${device.id}`);
})
.catch((e: IntentFlow.HandlerError) => {
e.errorCode = e.errorCode || 'invalid_request';
response.setErrorState(device.id, e.errorCode);
console.error('An error occurred sending the command', e.errorCode);
});
});
return Promise.all(promises)
.then(() => {
return response.build();
})
.catch((e) => {
const err = new IntentFlow.HandlerError(request.requestId,
'invalid_request', e.message);
return Promise.reject(err);
});
}
編譯 TypeScript 應用程式
前往 local/
目錄,然後執行下列指令,以下載 TypeScript 編譯器並編譯應用程式:
cd local npm install npm run build
這會編譯 index.ts
(TypeScript) 來源,並將下列內容放入 public/local-home/
目錄:
bundle.js
:包含本機應用程式和依附元件的編譯 JavaScript 輸出內容。index.html
:用於在裝置端測試應用程式的本機代管頁面。
部署測試專案
將更新後的專案檔案部署至 Firebase 託管,以便透過 Google Home 裝置存取這些檔案。
firebase deploy --only hosting
7. 啟動智慧型洗衣機
接下來,請測試本地執行要求應用程式與智慧型洗衣機之間的通訊了!程式碼研究室的入門專案包含以 Node.js 編寫的 動態智慧型洗衣機,可模擬使用者在本機控制的智慧型洗衣機。
設定裝置
您必須將虛擬裝置設為使用,在 Actions 主控台透過掃描設定探索裝置的 UDP 參數。此外,您還需要告知虛擬裝置要回報的本機裝置 ID,以及在裝置狀態變更時用於回報狀態事件的動作專案 ID。
參數 | 建議值 |
deviceId |
|
discoveryPortOut |
|
discoveryPacket |
|
projectId | 您的 Actions 專案 ID |
啟動裝置
前往 virtual-device/
目錄並執行裝置指令碼,將設定參數做為引數傳遞:
cd virtual-device npm install npm start -- \ --deviceId=deviceid123 --projectId=<project-id> \ --discoveryPortOut=3311 --discoveryPacket=HelloLocalHomeSDK
確認裝置指令碼是否使用預期的參數執行:
(...): UDP Server listening on 3311 (...): Device listening on port 3388 (...): Report State successful
8. 對 TypeScript 應用程式進行偵錯
在下一節中,您將確認 Google Home 裝置能夠透過區域網路正確掃描與識別,並將指令傳送至虛擬智慧洗衣機。您可以使用 Google Chrome 開發人員工具連線至 Google Home 裝置、查看控制台記錄,以及對 TypeScript 應用程式偵錯。
連結 Chrome 開發人員工具
如要將偵錯工具連結至本機執行要求應用程式,請按照下列步驟操作:
- 確認已將 Google Home 裝置連結至有權存取 Actions 主控台專案的使用者。
- 重新啟動您的 Google Home 裝置,該裝置才能取得 HTML 網址,以及您在 Actions 主控台執行的掃描設定。
- 在開發機器上啟動 Chrome。
- 開啟新的 Chrome 分頁,並在網址欄位中輸入
chrome://inspect
即可啟動檢查器。
頁面上應會顯示裝置清單,且應用程式網址應顯示在 Google Home 裝置的名稱下方。
啟動檢查器
按一下應用程式網址下方的「檢查」,啟動 Chrome 開發人員工具。選取「Console」分頁標籤,並確認您可看到 TypeScript 應用程式顯示的 IDENTIFY
意圖內容。
此輸出內容代表成功探索並識別虛擬裝置,並辨識本機執行要求應用程式。
測試本地執行要求
您可以使用 Google Home 應用程式中的觸控設定或語音指令,向 Google Home 裝置傳送指令,例如:
「Ok Google,打開洗衣機。」
「Ok Google,啟動洗衣機。」
「Ok Google,停止洗衣機。」
這麼做應會觸發平台將 EXECUTE
意圖傳送至 TypeScript 應用程式。
確認每個指令都可以顯示本機智慧型洗衣機狀態變更。
... ***** The washer is RUNNING ***** ... ***** The washer is STOPPED *****
9. 恭喜
恭喜!您已使用 Local Home SDK 將本地執行要求整合至智慧型住宅動作。
瞭解詳情
您還可以試試以下其他功能:
- 變更掃描設定,並讓掃描設定生效。例如改用其他 UDP 通訊埠或探索封包。
- 修改虛擬裝置程式碼集,在嵌入式裝置 (例如 Raspberry Pi) 上執行,並使用 LED 或螢幕視覺化目前狀態。