欢迎使用 Google Home 开发者中心,您可以在这里学习有关如何开发智能家居 Action 的新平台。注意:你将继续在 Actions 控制台中构建操作。

调试 Local Home

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

1. 准备工作

通过智能家居集成,Google 助理可以控制用户住宅中已连接的设备。如要构建智能家居 Action,您需要提供一个能够处理智能家居 intent 的云网络钩子端点。例如,当用户说“Ok Google,打开灯”时,Google 助理会将这条指令发给您的云执行方式,以更新设备状态。

Local Home SDK 可以增强智能家居集成。它添加了一条本地路径,能直接将智能家居 intent 传递给 Google Home 设备,从而提高可靠性并缩短处理用户指令时的延迟时间。借助此 SDK,您可以用 TypeScript 或 JavaScript 编写和部署本地执行方式应用,以识别设备并在任意一个 Google Home 智能音箱或 Google Nest 智能显示屏上执行指令。然后,您的应用使用现有的标准协议,通过局域网直接与用户的现有智能设备进行通信,以便执行指令。

72ffb320986092c.png

调试智能家居 Action 是打造具有生产质量的 Action 的关键步骤,但如果没有富含信息、易于使用的问题排查和测试工具,那么挑战既耗时又耗费时间。为方便调试智能家居 Action,我们提供了 Google Cloud Platform (GCP) 指标和日志记录以及 Smart Home 测试套件,可帮助您识别和解决 Action 的问题。

前提条件

构建内容

在此 Codelab 中,您将为智能家居 Action 构建本地执行方式,并将其连接到 Google 助理,然后通过测试套件对智能家居和 Google Cloud Platform (GCP) 指标和日志记录进行调试。

学习内容

  • 如何使用 GCP 指标和 Logging 找出和解决生产环境中的问题。
  • 如何使用测试套件来识别功能和 API 问题?
  • 如何在开发 Local Home 应用时使用 Chrome 开发者工具。

所需条件

2. 运行洗衣机应用

获取源代码

点击以下链接,将此 Codelab 的示例下载到您的开发机器上:

…或者,您也可以通过命令行克隆 GitHub 代码库:

$ git clone https://github.com/googlecodelabs/smarthome-debug-local.git

项目简介

起始应用包含与为智能家居 Action 启用本地执行方式 Codelab 类似的子目录和 Cloud Functions 函数。不过,我们可以使用 app-faulty,而不是 app-start。我们将从本地家居应用开始,但行之有效。

关联到 Firebase

我们将使用你在为智能家居 Action 启用本地执行方式 Codelab 中创建的项目,但我们将部署在此 Codelab 中下载的文件。

导航到 app-faulty 目录,然后使用在为智能家居 Action 启用本地执行方式 Codelab 中创建的 Action 项目设置 Firebase CLI:

$ cd app-faulty
$ firebase use <project-id>

部署到 Firebase

转到 app-faulty/functions 文件夹,然后使用 npm 安装所有必要的依赖项:

$ cd functions
$ npm install

注意:如果您看到以下消息,可以忽略并继续。出现此警告是由于一些较旧的依赖项所致,您可以点击此处查看更多详细信息。

found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details

转到 app-faulty/local/ 目录并运行以下命令,以下载 TypeScript 编译器并编译应用:

$ cd ../local
$ npm install
$ npm run build

这会编译 index.ts (TypeScript) 源代码,并将以下内容放入 app-faulty/public/local-home/ 目录:

  • bundle.js - 已编译的 JavaScript 输出,包含本地应用和依赖项。
  • index.html - 用于提供应用以在设备上进行测试的本地托管网页。

依赖性安装完毕且配置好项目后,您就可以首次运行此应用了。

$ firebase deploy

您应该会看到以下控制台输出:

...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/<project-id>/overview
Hosting URL: https://<projectcd -id>.web.app

此命令会部署一个 Web 应用以及几个 Cloud Functions for Firebase

更新 HomeGraph

在你的浏览器 (https://<project-id>.web.app) 中打开 Hosting 网址 以查看 Web 应用。在网页界面上,点击 Refresh ae8d3b25777a5e30.png 按钮,通过 Request Sync 使用故障洗衣机应用的最新设备元数据更新 HomeGraph:

fa3c47f293cfe0b7.png

打开 Google Home 应用,验证您是否能看到新名称“洗衣机清洗设备”的洗衣机设备。请务必将设备分配给包含 Nest 设备的房间。

2a082ee11d47ad1a.png

3. 启动智能洗衣机

如果你已运行为智能家居 Action 启用本地执行方式 Codelab,你应该已经启动了虚拟智能洗衣机。如果已停止,请记得重启虚拟设备。

启动设备

转到 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

4. 测试 Local Home 应用

通过语音指令向 Google Home 设备发送指令,例如:

“Ok Google,打开洗衣机。”

“Ok Google,启动洗衣机。”

“Ok Google,强制本地”。

“Ok Google,停止洗衣机。”

您会发现,在“强制本地安装”后尝试控制洗衣机时,Google 助理给出了“抱歉,似乎洗衣机暂时不可用”这条消息。

这意味着,设备无法通过本地路径访问。它在发出“Ok Google,强制使用本地”之前就起作用了,因为当无法通过本地路径访问设备时,我们会回退到使用云路径。不过,在“强制使用本地”后,回退到云端路径的选项将被停用。

为了找出问题所在,请充分利用我们提供的工具:Google Cloud Platform (GCP) 指标和日志记录以及 Chrome 开发者工具。

5. 调试 Local Home 应用

在下一部分中,您将使用 Google 提供的工具来查明设备无法通过本地路径访问的原因。你可以使用 Google Chrome 开发者工具连接到 Google Home 设备、查看控制台日志和调试 Local Home 应用。你还可以向 Cloud Logging 发送自定义日志,以便了解你的 Local Home 应用发现的主要错误。

关联 Chrome 开发者工具

如需将调试程序关联到您的本地执行方式应用,请按照以下步骤操作:

  1. 确保您已将 Google Home 设备与有权访问 Actions 控制台项目的用户相关联。
  2. 重新启动 Google Home 设备,使其能够获取您的 HTML 的网址,以及您在 Actions 控制台中添加的扫描配置。
  3. 在开发机器上启动 Chrome。
  4. 打开新的 Chrome 标签页,然后在地址字段中输入 chrome://inspect 以启动检查器。

您应该会在页面上看到设备列表,并且您的应用网址应该会出现在您的 Google Home 设备名称下方。

567f97789a7d8846.png

启动检查器

点击应用网址下方的 Inspect,以启动 Chrome 开发者工具。选择 Console 标签页,并验证您是否可以看到您的 TypeScript 应用输出的 IDENTIFY intent 内容。

774c460c59f9f84a.png

此输出表示 IDENTIFY 处理程序已成功触发,但 IdentifyReponse 中返回的 verificationId 与 HomeGraph 中的任何设备都不匹配。让我们添加一些自定义日志来找出原因。

添加自定义日志

虽然 Local Home SDK 会输出 DEVICE_VERIFICATION_FAILED 错误,但这对查找根本原因没有任何帮助。添加一些自定义日志,以确保我们正确读取和处理扫描数据。请注意,如果我们拒绝该 promise 并抛出错误,该错误消息实际上也会发送到 Cloud Logging

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.
  // Is there something wrong here?
  const localDeviceId = Buffer.from(scanData.data);
  console.log(`IDENTIFY handler: received local device id 
      ${localDeviceId}`);

  // Add custom logs
  if (!localDeviceId.toString().match(/^deviceid[0-9]{3}$/gi)) {
    const err = new IntentFlow.HandlerError(request.requestId,  
        'invalid_device', 'Invalid device id from scan data ' + 
        localDeviceId);
    return Promise.reject(err);
  }

  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);
}

此外,更改本地 Home 应用版本,以便我们确定是否使用了正确的版本。

local/index.ts

const localHomeSdk = new App('1.0.1');

添加自定义日志后,您需要重新编译应用并重新部署到 Firebase。

$ cd ../app-faulty/local
$ npm run build
$ firebase deploy --only hosting

现在,重新启动 Google Home 设备,以便其加载更新后的本地家居应用。你可以查看 Chrome 开发者工具中的 Console 日志,了解 Google Home 设备使用的是否是预期的版本。

ecc56508ebcf9ab.png

访问 Cloud Logging

我们来看一下如何使用 Cloud Logging 查找错误。如需访问你的项目的 Cloud Logging,请按以下步骤操作:

  1. 在 Cloud Platform 控制台中,转到项目页面。
  2. 选择你的智能家居项目。
  3. 运维下,选择 Logging > 日志浏览器

通过 Identity and Access Management (IAM) 管理你的 Actions 项目用户对日志数据的访问权限。如需详细了解日志记录数据的角色和权限,请参阅 Cloud Logging 访问权限控制

使用高级过滤条件

我们知道,IDENTIFY intent 中会出现错误,因为本地设备未能识别,因为无法识别本地设备。不过,我们希望知道问题具体是什么,因此请先滤除 IDENTIFY 处理程序中发生的错误。

展开查询预览框,它应该会变成一个查询构建器框。在查询构建器框中输入 jsonPayload.intent="IDENTIFY",然后点击运行查询按钮。

4c0b9d2828ee2447.png

因此,您会获取 IDENTIFY 处理程序中抛出的所有错误日志。接下来,展开最后一个错误。您将在 IDENTIFY 处理程序中找到刚刚拒绝 promise 时设置的 errorCodedebugString

71f2f156c6887496.png

debugString 中,我们可以知道本地设备 ID 不符合预期格式。Local Home 应用应该会以字符串开头获取本地设备 ID,该 ID 应以 deviceid 开头,后跟 3 位数字,但此处的本地设备 ID 是一个十六进制字符串。

修正错误

回到从扫描数据解析本地设备 ID 的源代码,我们注意到,在将字符串转换为字节时,我们并未提供编码。扫描数据以十六进制字符串的形式接收,因此在调用 Buffer.from() 时传递 hex 作为字符编码。

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');
  console.log(`IDENTIFY handler: received local device id 
      ${localDeviceId}`);

  if (!localDeviceId.toString().match(/^deviceid[0-9]{3}$/gi)) {
    const err = new IntentFlow.HandlerError(request.requestId,  
      'invalid_device', 'Invalid device id from scan data ' + 
      localDeviceId);
    return Promise.reject(err);
  }

  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);
}

此外,更改本地 Home 应用版本,以便我们确定是否使用了正确的版本。

local/index.ts

const localHomeSdk = new App('1.0.2');

修正错误后,请编译应用并重新部署到 Firebase。在 app-faulty/local 中,运行以下命令:

$ npm run build
$ firebase deploy --only hosting

测试修正效果

完成部署后,重新启动 Google Home 设备,以便其加载更新后的本地家居应用。请确保本地住宅应用版本为 1.0.2,并且这一次您应该不会在 Chrome 开发者工具控制台中看到任何错误。

c8456f7b5f77f894.png

现在,您可以再次尝试向您的设备发送命令。

“Ok Google,强制本地。”

“Ok Google,停止洗衣机。”

“Ok Google,打开洗衣机。”

……

“Ok Google,强制默认。”

6. 运行智能家居测试套件

使用 Google Home 应用中的触控功能或通过语音指令验证设备后,你可以使用自动化的智能家居测试套件,根据与 Action 关联的设备类型和特征来验证用例。测试套件会运行一系列测试来检测 Action 中的问题,并会显示失败测试用例的信息性消息,在调试事件日志之前加快调试速度。

运行智能家居测试套件

如需测试测试套件的智能家居 Action,请按照以下说明操作:

  1. 在网络浏览器中,打开智能家居测试套件
  2. 使用右上角的按钮登录 Google。这样,测试套件就可以将命令直接发送到 Google 助理。
  3. Project ID 字段中,输入智能家居 Action 的项目 ID。然后点击下一步以继续操作。
  4. Test Settings 步骤中,您应在 Devices and Trais 部分看到 Faulty Washer。
  5. 停用 Test Request Sync 选项,因为示例洗衣机应用没有任何用于添加 / 移除 / 重命名洗衣机的界面。在生产系统中,每当用户添加/移除/重命名设备时,您都必须触发请求同步
  6. 保持“Local Home SDK”选项保持启用状态,因为我们将同时测试本地路径和云路径。
  7. 点击下一步以开始运行测试。

67433d9190fa770e.png

测试完成后,您会注意到,本地路径中的暂停/恢复测试在通过云路径中的暂停/恢复测试时失败了。

d1ebd5cfae2a2a47.png

分析错误消息

仔细查看失败测试用例中的错误消息。它们告诉您测试的预期状态是什么,实际状态是什么。在本例中,对于“Pause the Washer”(暂停洗衣机),预期状态是 isPaused: true,但在实际状态下,状态是 isPaused: false。同样,对于“Pause the Washer”(暂停洗衣机),预期状态是 isPaused: true,但在实际状态下,状态却是 isPaused: false

6bfd3acef9c16b84.png

根据错误消息,我们似乎在本地路径中设置了相反的 isPaused 状态。

找出并修正错误

让我们找到 Local Home 应用将执行命令发送到设备的源代码。getDataCommand()executeHandler() 调用的函数,用于在发送给设备的执行命令中设置 payload

local/index.ts

getDataForCommand(command: string, params: IWasherParams): unknown {
    switch (command) {
        case 'action.devices.commands.OnOff':
            return {
                on: params.on ? true : false
            };
        case 'action.devices.commands.StartStop':
            return {
                isRunning: params.start ? true : false
            };
        case 'action.devices.commands.PauseUnpause':
            return {
                // Is there something wrong here?
                isPaused: params.pause ? false : true
            };
        default:
            console.error('Unknown command', command);
            return {};
    }
}

我们确实将 isPause 设置为反向状态,当 params.pausetrue 时,应将其设置为 true,否则设置为 false。让我们解决这个问题。

local/index.ts

getDataForCommand(command: string, params: IWasherParams): unknown {
    switch (command) {
        case 'action.devices.commands.OnOff':
            return {
                on: params.on ? true : false
            };
        case 'action.devices.commands.StartStop':
            return {
                isRunning: params.start ? true : false
            };
        case 'action.devices.commands.PauseUnpause':
            return {
                isPaused: params.pause ? true : false
            };
        default:
            console.error('Unknown command', command);
            return {};
    }
}

更改本地 Home 应用版本,以便我们确定是否使用了正确的版本。

local/index.ts

const localHomeSdk = new App('1.0.3');

请记得再次编译应用,然后重新部署到 Firebase。在 app-faulty/local 中,运行以下命令:

$ npm run build
$ firebase deploy --only hosting

现在,重新启动 Google Home 设备,以便其加载更新后的本地家居应用。确保本地住宅应用版本为 1.0.3。

测试修正效果

现在,使用相同的配置重新运行智能家居测试套件,您会发现所有测试用例均已通过。

b7fc8c5d3c727d8d.png

7. 恭喜

764dbc83b95782a.png

恭喜!您已成功了解如何通过测试套件对智能家居和 Cloud Logging 进行问题排查。

了解详情

您还可以尝试下面这些操作:

您还可以详细了解如何测试和提交 Action 以供审核,包括用于向用户发布 Action 的认证流程。