1. 准备工作
云到云集成使用设备类型来让 Google 助理了解对某个设备应该使用哪种语法。设备特征定义各个设备类型的功能。设备可继承添加到集成的每个设备特征的状态。
您可以将任何支持的特征关联到您选择的设备类型,以便自定义用户设备的功能。如果您想在 Action 中实现目前设备架构中并未提供的自定义 trait,则 Modes 和 Toggle trait 允许使用您定义的自定义名称来控制特定设置。
除了按类型和特征提供的基本控制功能以外,Smart Home API 还提供其他用于完善用户体验的功能。当 intent 未成功实现时,错误响应可提供详细的用户反馈。通过第二层用户身份验证,您可以扩展这些响应,并增强您所选设备特征的安全性。通过发送特定错误响应验证 Google 助理发出的阻止后,您的云到云集成可能需要其他授权才能完成相应命令。
前提条件
构建内容
在此 Codelab 中,您将利用 Firebase 部署一个预构建的智能家居集成,然后学习如何向智能家居洗衣机添加针对负荷容量和涡轮模式的非标准特征。您还将实现错误和异常报告,并学习如何使用第二层用户身份验证强制执行语音确认以开启洗衣机。
学习内容
- 如何向集成添加“Modes”和“Toggles”trait
- 如何报告错误和异常
- 如何申请第二层用户身份验证
所需条件
- 网络浏览器,例如 Google Chrome
- 安装了 Google Home 应用的 iOS 或 Android 设备
- Node.js 10.16 或更高版本
- Google 账号
- Google Cloud 结算账号
2. 开始使用
启用活动控件
若要使用 Google 助理,你必须与 Google 分享某些活动数据。Google 助理需要使用这些数据才能正常运行;然而,分享数据的要求并非专门针对该 SDK。如果你还没有 Google 账号,请创建一个 Google 账号,以便分享这些数据。你可以使用任何 Google 账号,不要求必须用你的开发者账号。
打开要与 Google 助理搭配使用的 Google 账号的活动控件页面。
确保已启用以下切换开关:
- 网络与应用活动记录 - 此外,请务必选中包括 Chrome 历史记录和使用 Google 服务的网站、应用和设备中的活动记录复选框。
- 设备信息
- 语音和音频活动记录
创建云到云集成项目
- 前往开发者控制台。
- 点击 Create Project,输入项目名称,然后点击 Create Project。
选择云到云集成
在 Play 管理中心的项目首页上,选择云到云下的添加云到云集成。
安装 Firebase CLI
借助 Firebase 命令行界面 (CLI),您可以在本地提供 Web 应用,并将您的 Web 应用部署到 Firebase Hosting。
如需安装 CLI,请从终端运行以下 npm 命令:
npm install -g firebase-tools
如需验证 CLI 是否已正确安装,请运行以下命令:
firebase --version
运行以下命令,授权您的 Google 账号使用 Firebase CLI:
firebase login
将 Firebase 添加到您的 Google Home 开发者控制台项目
方法 1:通过 Firebase 控制台
- 前往 Firebase。
- 点击创建 Firebase 项目。
- 在创建项目界面上,点击将 Firebase 添加到 Google Cloud 项目。
- 在开始界面上,选择您在 Google Home 开发者控制台中刚刚创建的 Google Cloud 项目,然后点击继续。
方法 2:通过 Firebase Click
将新的 Firebase 项目添加到您的 Google Home 开发者控制台项目后,该项目将显示在 Firebase 控制台中。Firebase 项目的项目 ID 将与您的 Google Home 开发者控制台项目 ID 保持一致。
启用 HomeGraph API
借助 HomeGraph API,您可以在用户 Home Graph 中存储并查询设备及其状态。如需使用此 API,您必须先打开 Google Cloud 控制台,然后启用 HomeGraph API。
在 Google Cloud Console 中,请务必选择与您的 Actions <firebase-project-id>.
相匹配的项目。然后,在 HomeGraph API 的 API 库屏幕中,点击启用。
3. 运行入门级应用
开发环境设置完毕后,你可以部署入门级项目以验证所有设置是否已配置正确。
获取源代码
点击以下链接,将此 Codelab 的示例下载到您的开发机器上:
…或者,您也可以通过命令行克隆 GitHub 代码库:
git clone https://github.com/google-home/smarthome-traits.git
解压下载的 ZIP 文件。
项目简介
入门级项目包含以下子目录:
public:
一种前端界面,可轻松地控制和监控智能洗衣机的状态。functions:
一种已全面实现的云服务,可使用 Cloud Functions for Firebase 和 Firebase Realtime Database 来管理智能洗衣机。
提供的云执行方式在 index.js
中包括以下函数:
fakeauth
:用于账号关联的授权端点faketoken
:用于账号关联的令牌端点smarthome
:智能家居 intent 执行方式端点reportstate
:在设备状态改变时调用 Home Graph APIrequestsync
:允许用户设备进行更新,而无需重新关联账号
连接到 Firebase
前往 washer-start
目录,然后使用您的集成项目设置 Firebase CLI:
cd washer-start firebase use <project-id>
配置 Firebase 项目
初始化 Firebase 项目。
firebase init
选择 CLI 功能 Realtime Database、Functions 以及包含 Firebase 托管的 Hosting 功能。
? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed) >( ) Data Connect: Set up a Firebase Data Connect service ( ) Firestore: Configure security rules and indexes files for Firestore ( ) Genkit: Setup a new Genkit project with Firebase (*) Functions: Configure a Cloud Functions directory and its files ( ) App Hosting: Configure an apphosting.yaml file for App Hosting (*) Hosting: Configure files for Firebase Hosting and (optionally) 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 (*) Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance ( ) Data Connect: Set up a Firebase Data Connect service ( ) Firestore: Configure security rules and indexes files for Firestore
这将初始化项目的必要 API 和功能。
在系统显示提示时,初始化 Realtime Database。你可以使用数据库实例的默认位置。
? 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
如果您要重新初始化项目,则在系统询问您是否要初始化或覆盖 functions/.gitignore 时,选择 No。
? File functions/.gitignore already exists. Overwrite? No
? Do you want to install dependencies with npm now? Yes
最后,配置 Hosting 设置以便使用项目代码中的 public
目录,并使用现有的 index.html 文件。当系统要求您使用 ESLint 时,请选择否。
? 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 deploy
您应该会看到以下控制台输出:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<project-id>/overview Hosting URL: https://<project-id>.web.app
此命令会部署一个 Web 应用以及几个 Cloud Functions for Firebase。
在浏览器 (https://<firebase-project-id>.web.app
) 中打开托管网址以查看此 Web 应用。您会看到以下界面:
此网络界面表示用于查看或修改设备状态的第三方平台。如需使用设备信息填充数据库,请点击 UPDATE。此页面不会显示任何更改,但洗衣机的当前状态会存储在数据库中。
现在,您可以使用 Developer Console 将您部署的云服务关联到 Google 助理。
配置您的 Play 管理中心项目
在 Develop 标签页中,为您的互动添加显示名称。此名称会显示在 Google Home 应用中。
在应用品牌信息下,为应用图标上传一个大小为 144 x 144 像素且名为
的 png
文件。
如需启用账号关联,请使用以下账号关联设置:
客户 ID |
|
客户端密钥 |
|
授权网址 |
|
令牌网址 |
|
在 Cloud fulfillment 网址 下,输入为智能家居 intent 提供执行方式的 Cloud Functions 函数的网址。
https://us-central1-<firebase-project-id>.cloudfunctions.net/smarthome
点击 Save 保存您的项目配置,然后点击 Next: Test 针对您的项目启用测试。
现在,您可以开始实现必要的网络钩子,以便将设备状态关联到 Google 助理。
关联到 Google 助理
为了测试云到云集成,您需要将项目与 Google 账号相关联。这样一来,您就可以使用登录同一账号的 Google 助理界面和 Google Home 应用来进行测试。
- 在手机上打开 Google 助理设置。请注意,您登录的账号应该与控制台所用的账号相同。
- 依次转到 Google 助理 > 设置 > 家居控制(位于“Google 助理”下方)。
- 点击右上角的搜索图标。
- 使用 [test] 前缀搜索测试应用,以查找特定的测试应用。
- 选择此项目。然后,Google 助理会通过您的服务进行身份验证并发送
SYNC
请求,以要求您的服务提供用户设备列表。
打开 Google Home 应用,然后验证您能否看到相应洗衣机设备。
验证您是否可以在 Google Home 应用中通过语音指令控制洗衣机。您还应该会在云执行方式的前端网络界面中看到设备状态更改情况。
现在,您已经部署了一个基础洗衣机,接下来,您可以自定义设备上的可用模式。
4. 添加模式
action.devices.traits.Modes
特征可让设备针对一种模式提供任意数量的设置(一次只能设定一项设置)。您可以向洗衣机添加模式,以便定义洗衣负荷容量:小、中或大。
更新 SYNC 响应
您需要向 functions/index.js
中的 SYNC
响应添加新特征的相关信息。这些数据会显示在 traits
数组和 attributes
对象中,如以下代码段所示。
index.js
app.onSync(body => {
return {
requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
payload: {
agentUserId: USER_ID,
devices: [{
id: 'washer',
type: 'action.devices.types.WASHER',
traits: [
'action.devices.traits.OnOff',
'action.devices.traits.StartStop',
'action.devices.traits.RunCycle',
// Add Modes trait
'action.devices.traits.Modes',
],
name: { ... },
deviceInfo: { ... },
attributes: {
pausable: true,
//Add availableModes
availableModes: [{
name: 'load',
name_values: [{
name_synonym: ['load'],
lang: 'en',
}],
settings: [{
setting_name: 'small',
setting_values: [{
setting_synonym: ['small'],
lang: 'en',
}]
}, {
setting_name: 'medium',
setting_values: [{
setting_synonym: ['medium'],
lang: 'en',
}]
}, {
setting_name: 'large',
setting_values: [{
setting_synonym: ['large'],
lang: 'en',
}]
}],
ordered: true,
}],
},
}],
},
};
});
添加新的 EXECUTE intent 命令
在 EXECUTE
intent 中添加 action.devices.commands.SetModes
命令,如以下代码段所示。
index.js
const updateDevice = async (execution,deviceId) => {
const {params,command} = execution;
let state, ref;
switch (command) {
case 'action.devices.commands.OnOff':
state = {on: params.on};
ref = firebaseRef.child(deviceId).child('OnOff');
break;
case 'action.devices.commands.StartStop':
state = {isRunning: params.start};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.PauseUnpause':
state = {isPaused: params.pause};
ref = firebaseRef.child(deviceId).child('StartStop');
Break;
// Add SetModes command
case 'action.devices.commands.SetModes':
state = {load: params.updateModeSettings.load};
ref = firebaseRef.child(deviceId).child('Modes');
break;
}
};
更新 QUERY 响应
接下来,更新 QUERY
响应,以便报告洗衣机的当前状态。
将更新后的更改添加到 queryFirebase
和 queryDevice
函数以获取存储在 Realtime Database 中的状态。
index.js
const queryFirebase = async (deviceId) => {
const snapshot = await firebaseRef.child(deviceId).once('value');
const snapshotVal = snapshot.val();
return {
on: snapshotVal.OnOff.on,
isPaused: snapshotVal.StartStop.isPaused,
isRunning: snapshotVal.StartStop.isRunning,
// Add Modes snapshot
load: snapshotVal.Modes.load,
};
};
const queryDevice = async (deviceId) => {
const data = await queryFirebase(deviceId);
return {
on: data.on,
isPaused: data.isPaused,
isRunning: data.isRunning,
currentRunCycle: [{ ... }],
currentTotalRemainingTime: 1212,
currentCycleRemainingTime: 301,
// Add currentModeSettings
currentModeSettings: {
load: data.load,
},
};
};
更新报告状态
最后,更新 reportstate
函数,以便将洗衣机的当前负荷设置报告给 Home Graph。
index.js
const requestBody = {
requestId: 'ff36a3cc', /* Any unique ID */
agentUserId: USER_ID,
payload: {
devices: {
states: {
/* Report the current state of your washer */
[context.params.deviceId]: {
on: snapshot.OnOff.on,
isPaused: snapshot.StartStop.isPaused,
isRunning: snapshot.StartStop.isRunning,
// Add currentModeSettings
currentModeSettings: {
load: snapshot.Modes.load,
},
},
},
},
},
};
部署到 Firebase
运行以下命令以部署更新后的集成:
firebase deploy --only functions
部署完成后,前往 Web 界面,然后点击工具栏中的 Refresh 按钮。这会触发请求同步操作,以便 Google 助理接收更新后的
SYNC
响应数据。
现在,您可以发出一个命令来设置洗衣机的模式,例如:
“Ok Google, set the washer load to large.”(Ok Google,把洗衣机负荷容量设为大。)
此外,您还可以提出有关洗衣机的问题,例如:
“Ok Google, what is the washer load?”(Ok Google,洗衣机的负荷容量是多少?)
5. 添加切换开关
action.devices.traits.Toggles
特征表示设备的具有 true 或 false 状态的已命名方面,例如洗衣机是否处于涡轮模式。
更新 SYNC 响应
在 SYNC
响应中,您需要添加有关新设备特征的信息。这些信息将显示在 traits
数组和 attributes
对象中,如以下代码段所示。
index.js
app.onSync(body => {
return {
requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
payload: {
agentUserId: USER_ID,
devices: [{
id: 'washer',
type: 'action.devices.types.WASHER',
traits: [
'action.devices.traits.OnOff',
'action.devices.traits.StartStop',
'action.devices.traits.RunCycle',
'action.devices.traits.Modes',
// Add Toggles trait
'action.devices.traits.Toggles',
],
name: { ... },
deviceInfo: { ... },
attributes: {
pausable: true,
availableModes: [{
name: 'load',
name_values: [{
name_synonym: ['load'],
lang: 'en'
}],
settings: [{ ... }],
ordered: true,
}],
//Add availableToggles
availableToggles: [{
name: 'Turbo',
name_values: [{
name_synonym: ['turbo'],
lang: 'en',
}],
}],
},
}],
},
};
});
添加新的 EXECUTE intent 命令
在 EXECUTE
intent 中添加 action.devices.commands.SetToggles
命令,如以下代码段所示。
index.js
const updateDevice = async (execution,deviceId) => {
const {params,command} = execution;
let state, ref;
switch (command) {
case 'action.devices.commands.OnOff':
state = {on: params.on};
ref = firebaseRef.child(deviceId).child('OnOff');
break;
case 'action.devices.commands.StartStop':
state = {isRunning: params.start};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.PauseUnpause':
state = {isPaused: params.pause};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.SetModes':
state = {load: params.updateModeSettings.load};
ref = firebaseRef.child(deviceId).child('Modes');
break;
// Add SetToggles command
case 'action.devices.commands.SetToggles':
state = {Turbo: params.updateToggleSettings.Turbo};
ref = firebaseRef.child(deviceId).child('Toggles');
break;
}
更新 QUERY 响应
最后,您需要更新 QUERY
响应以报告洗衣机的涡轮模式。将更新后的更改添加到 queryFirebase
和 queryDevice
函数以获取存储在 Realtime Database 中的切换状态。
index.js
const queryFirebase = async (deviceId) => {
const snapshot = await firebaseRef.child(deviceId).once('value');
const snapshotVal = snapshot.val();
return {
on: snapshotVal.OnOff.on,
isPaused: snapshotVal.StartStop.isPaused,
isRunning: snapshotVal.StartStop.isRunning,
load: snapshotVal.Modes.load,
// Add Toggles snapshot
Turbo: snapshotVal.Toggles.Turbo,
};
}
const queryDevice = async (deviceId) => {
const data = queryFirebase(deviceId);
return {
on: data.on,
isPaused: data.isPaused,
isRunning: data.isRunning,
currentRunCycle: [{ ... }],
currentTotalRemainingTime: 1212,
currentCycleRemainingTime: 301,
currentModeSettings: {
load: data.load,
},
// Add currentToggleSettings
currentToggleSettings: {
Turbo: data.Turbo,
},
};
};
更新报告状态
最后,更新 reportstate
函数,以便向洗衣机报告洗衣机是否已设为涡轮模式。
index.js
const requestBody = {
requestId: 'ff36a3cc', /* Any unique ID */
agentUserId: USER_ID,
payload: {
devices: {
states: {
/* Report the current state of your washer */
[context.params.deviceId]: {
on: snapshot.OnOff.on,
isPaused: snapshot.StartStop.isPaused,
isRunning: snapshot.StartStop.isRunning,
currentModeSettings: {
load: snapshot.Modes.load,
},
// Add currentToggleSettings
currentToggleSettings: {
Turbo: snapshot.Toggles.Turbo,
},
},
},
},
},
};
部署到 Firebase
运行以下命令以部署更新后的函数:
firebase deploy --only functions
部署完成后,点击网络界面中的 Refresh 按钮以触发请求同步。
现在,您可以说出指令,以便将洗衣机设为涡轮模式:
“Hey Google,将洗衣机设为涡轮模式。”
您还可以提出以下问题,以便检查洗衣机是否已处于涡轮模式:
“Ok Google, is my washer in turbo mode?”(Ok Google,我的洗衣机开启涡轮模式了吗?)
6. 报告错误和异常
借助云到云集成中的错误处理功能,您可以在有问题导致 EXECUTE
和 QUERY
响应失败时向用户报告相关信息。这些通知可在用户与您的智能设备和集成互动时为用户提供更积极的用户体验。
每当 EXECUTE
或 QUERY
请求失败时,您的集成都应返回错误代码。例如,如果您想在用户试图在机盖处于打开状态的情况下启动洗衣机时抛出错误,那么您的 EXECUTE
响应将如以下代码段所示:
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"commands": [
{
"ids": [
"456"
],
"status": "ERROR",
"errorCode": "deviceLidOpen"
}
]
}
}
现在,如果用户要求启动洗衣机,Google 助理会说出以下内容作为响应:
“The lid is open on the washer. Please close it and try again.”(洗衣机的机盖打开了。请关闭机盖,然后重试。)
异常与错误类似,但异常指示的是某个提醒与某个命令相关联的情况,这种情况未必会阻止顺利执行。异常可使用 StatusReport
特征提供相关信息,例如电池电量或近期状态更改。不会阻止执行的异常代码会随 SUCCESS
状态一起返回,而会阻止执行的异常代码会随 EXCEPTIONS
状态一起返回。
以下代码段中提供了包含异常的示例响应:
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"commands": [{
"ids": ["123"],
"status": "SUCCESS",
"states": {
"online": true,
"isPaused": false,
"isRunning": false,
"exceptionCode": "runCycleFinished"
}
}]
}
}
Google 助理会说出以下内容作为响应:
“The washer has finished running.”(洗衣机已结束运行。)
如需为您的洗衣机添加错误报告,请打开 functions/index.js
,然后添加错误类别定义,如以下代码段所示:
index.js
app.onQuery(async (body) => {...});
// Add SmartHome error handling
class SmartHomeError extends Error {
constructor(errorCode, message) {
super(message);
this.name = this.constructor.name;
this.errorCode = errorCode;
}
}
更新执行响应以返回错误代码和错误状态:
index.js
const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
for (const device of command.devices) {
for (const execution of command.execution) {
executePromises.push(
updateDevice(execution, device.id)
.then((data) => {
...
})
//Add error response handling
.catch((error) => {
functions.logger.error('EXECUTE', device.id, error);
result.ids.push(device.id);
if (error instanceof SmartHomeError) {
result.status = 'ERROR';
result.errorCode = error.errorCode;
}
})
);
}
}
}
现在,Google 助理可以告知用户您报告的任何错误代码了。在下一部分中,您会看到具体示例。
7. 添加第二层用户身份验证
如果您的设备具有任何需要安全保障或应限定特定授权用户群组使用的模式(例如软件更新或开锁),您应该在集成中实现第二层用户验证。
您可以针对所有设备类型和特征实现第二层用户身份验证,以便自定义是否每次都要进行安全验证,或是否需要满足特定条件。
No
challenge
- 不使用身份验证的请求和响应(这是默认行为)ackNeeded
- 需要进行显式确认(是或否)的第二层用户身份验证pinNeeded
- 需要输入个人识别码 (PIN) 的第二层用户身份验证
在本 Codelab 中,请向用于开启洗衣机的命令添加 ackNeeded
验证,并添加在次级验证失败时返回错误的功能。
打开 functions/index.js
,然后添加错误类别定义以返回错误代码和验证类型,如以下代码段所示:
index.js
class SmartHomeError extends Error { ... }
// Add secondary user verification error handling
class ChallengeNeededError extends SmartHomeError {
/**
* Create a new ChallengeNeededError
* @param {string} suvType secondary user verification challenge type
*/
constructor(suvType) {
super('challengeNeeded', suvType);
this.suvType = suvType;
}
}
此外,您还需要更新相应的执行响应以返回 challengeNeeded
错误,具体如下所示:
index.js
const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
for (const device of command.devices) {
for (const execution of command.execution) {
executePromises.push(
updateDevice(execution, device.id)
.then((data) => {
...
})
.catch((error) => {
functions.logger.error('EXECUTE', device.id, error);
result.ids.push(device.id);
if (error instanceof SmartHomeError) {
result.status = 'ERROR';
result.errorCode = error.errorCode;
//Add error response handling
if (error instanceof ChallengeNeededError) {
result.challengeNeeded = {
type: error.suvType
};
}
}
})
);
}
}
}
最后,修改 updateDevice
以要求通过显式确认来开启或关闭洗衣机。
index.js
const updateDevice = async (execution,deviceId) => {
const {challenge,params,command} = execution; //Add secondary user challenge
let state, ref;
switch (command) {
case 'action.devices.commands.OnOff':
//Add secondary user verification challenge
if (!challenge || !challenge.ack) {
throw new ChallengeNeededError('ackNeeded');
}
state = {on: params.on};
ref = firebaseRef.child(deviceId).child('OnOff');
break;
...
}
return ref.update(state)
.then(() => state);
};
部署到 Firebase
运行以下命令以部署更新后的函数:
firebase deploy --only functions
部署更新后的代码后,当您要求 Google 助理开启或关闭洗衣机时,您必须使用语音确认相应 Action,具体如下所示:
您:“Ok Google, turn on the washer.”(Ok Google,开启洗衣机。)
Google 助理:“Are you sure you want to turn on the washer?”(确定要开启洗衣机吗?)
您:“Yes.”(是的。)
此外,您还可以打开 Firebase 日志以查看辅助用户验证流程的每个步骤的详细响应。
8. 恭喜
恭喜!您已通过 Modes
和 Toggles
特征扩展了云到云集成的功能,并通过第二层用户验证确保其能够安全执行。
了解详情
您可以实现以下想法以进行更深入的研究:
- 向您的设备添加本地执行功能。
- 使用其他第二层用户身份验证质询类型来修改设备状态。
- 更新
RunCycle
特征 QUERY 响应以进行动态更新。 - 探索此 GitHub 示例。