将智能家居设备关联到 Google 助理

作为一名物联网 (IoT) 开发者,您可以构建智能家居 Action,让用户能够通过 Google Home 应用中的触控功能和 Google 助理的语音指令来控制设备。

79266e5f45e6ae20.gif

智能家居 Action 依靠 Home Graph 来提供住宅及其设备的环境数据,从而创建住宅逻辑图。借助这些环境数据,Google 助理能够根据用户在住宅中的位置更自然地理解用户请求。例如,Home Graph 可以存储客厅这个概念,而客厅中包含来自不同制造商的多种类型的设备(例如恒温器、灯、风扇和吸尘器)。

d009cef0f903d284.jpeg

前提条件

构建内容

在此 Codelab 中,您将发布一个用于管理虚拟智能洗衣机的云服务,然后构建一个智能家居 Action,并将其关联到 Google 助理。

学习内容

  • 如何部署智能家居云服务
  • 如何将您的服务关联到 Google 助理
  • 如何将设备状态更改发布到 Google

所需条件

启用活动控件

在您计划与 Google 助理搭配使用的 Google 帐号中启用以下活动控件

  • 网络与应用活动记录
  • 设备信息
  • 语音和音频活动记录

创建 Actions 项目

  1. 转到 Actions on Google 开发者控制台
  2. 点击 New Project,输入项目名称,然后点击 CREATE PROJECT

AWXw5E1m9zVgvVeyeL3uxwCX6DtWOCK6LRSLmOATFzjMbmE5cSWBdSVhJZDFpEFH2azZTK2eMs6OYYdMJYiGb5bKqFEzxaLyRUYuwVGBlSjXzTyy8Z9CvwpXvRwP7xdycklETzFc7Q

选择智能家居应用

在 Actions 控制台的“Overview”屏幕中,选择 Smart home

36RsBUWBgbgsa5xZ7MJVMm1sIg07nXbfjv0mWCxXViaC5SlbL2gMigw9hgXsZQhNMHLLFOfiKdZsSTNXONFB1i47gksw3SBNpkVYl492WeryOlgxKjpVrLAvg-5cZqu1DI-s5kxM3g

选择 Smart home 体验卡片,然后系统会将您转到项目控制台。

pzgHPsmc2LvLoeUvJfkjKQqD_BvO4v8JOPlcrxsmyptFkkjL4PP6LqrM9r5tNvEIfT9HmK-UKw3GWFPXTjqo4nUrhD2o5shUKHBE31OT8iIA69JZCev7_0_nh-lnL2oJHoxGfqqZ4w

安装 Firebase CLI

借助 Firebase 命令行界面 (CLI),您可以在本地提供 Web 应用,并将您的 Web 应用部署到 Firebase Hosting。

如需安装 CLI,请从终端运行以下 npm 命令:

npm install -g firebase-tools

如需验证 CLI 是否已正确安装,请运行以下命令:

firebase --version

运行以下命令,授权您的 Google 帐号使用 Firebase CLI:

firebase login

开发环境设置完毕后,您可以部署入门级项目以验证所有设置是否已配置正确。

获取源代码

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

下载源代码

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

git clone https://github.com/googlecodelabs/smarthome-washer.git

项目简介

入门级项目包含以下子目录:

  • public: 一种前端界面,可轻松地控制和监控智能洗衣机的状态。
  • functions: 一种已全面实现的云服务,可使用 Cloud Functions for Firebase 和 Firebase Realtime Database 来管理智能洗衣机。

关联到 Firebase

转到 washer-start 目录,然后使用您的 Actions 项目设置 Firebase CLI:

cd washer-start
firebase use <project-id>

部署到 Firebase

转到 functions 文件夹,然后使用 npm. 安装所有必要的依赖项

cd functions
npm install

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

firebase deploy

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

...

✔ Deploy complete!

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

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

在浏览器 (https://<project-id>.firebaseapp.com) 中打开托管网址以查看此 Web 应用。您会看到以下界面:

L60eA7MOnPmbBMl2XMipT9MdnP-RaVjyjf0Y93Y1b7mEyIsqZrrwczE7D3RQISRs-iusL1g4XbNmGhuA6-5sLcWefnczwNJEPfNLtwBsO4Tb9YvcAZBI6_rX19z8rxbik9Vq8F2fwg

此网络界面表示用于查看或修改设备状态的第三方平台。如需使用设备信息填充数据库,请点击 UPDATE。此页面不会显示任何更改,但洗衣机的当前状态会存储在数据库中。

现在,您可以通过 Actions 控制台将您部署的云服务关联到 Google 助理。

配置您的 Actions 控制台项目

Overview > Build your Action 下,选择 Add Action(s)。输入为智能家居 intent 提供执行方式的 Cloud Functions 函数的网址,然后点击 Save

https://us-central1-<project-id>.cloudfunctions.net/smarthome

Uso-o00XQXBHvOR9vQq9tmpYDYQJKsFEstsgRFnxPAJf7zJ2FxwhISiodo3dB1Tz49Okd6ivi66fjpo7rarS_GZelglGWCT1r9FzDGUl1r67ddIcIbQrxqN8jG9F9GAKOpk0Ckc-eA

Develop > Invocation 标签页中,在 Display name 中为您的 Action 添加显示名,然后点击 Save。此名称会显示在 Google Home 应用中。

gvC-TvmKDy-D-xjwkeCjNt__9ErA7DL8hZWa1oH1yPJ9SpYOepDYjxx6WnJ56IG-t37fJ65kmHISQdh72Ot2G-0tu6Flxf4gom5kvx_3hlvFeMqYuFgXr_85pfWWn7VLFHtS55p1zw

s4yc1kOW4XtKUQN1EYegiDLU5oTqmxQ2PNbeaujm26OQmYKKpjug7j5FYmutLSAZ1zBd-ZkcZlL7zyTZqw4bge3_oOeWvJTsqJ-A08vfZwImYQrKiquLskLuTpmMqXEZD1xchhCWGQ

如需启用帐号关联,请在左侧导航栏中依次选择 Develop > Account linking 选项。使用以下帐号关联设置:

客户端 ID

ABC123

客户端密钥

DEF456

授权网址

https://us-central1-<project-id>.cloudfunctions.net/fakeauth

令牌网址

https://us-central1-<project-id>.cloudfunctions.net/faketoken

rRyZTiBSTuPk3YtJtXjDK1pPftUxsaEhs9jzpvFtbHTD6bEwYxM8jV4MWxiljKA1bKVZrIRoO9O3jtBefLKf_OyMpukPjwIj8zGvyU3UwASzMrnRskl-hVAfAmQVi4sC_zAwgYwRXw

点击 Save 保存您的帐号关联配置,然后点击 Test 针对您的项目启用测试。

OgUvpQfXioygkRwPcaJpzjyNQDZy6enidUC8YMPaCOrZi0YeWCFsCJV9Gqg-_UfsqTnn4KEg--uE3Ymr0QuamDonF4RyYHtRKcULXABDuaEnj2hq8i20LYj1SrGP_1lQ_UsUB90pGw

系统会将您重定向到 Simulator。将鼠标指针悬停在“Testing on Device”(soCeBB1CkSIEqsBmDc8Cth6EjgcXUnrOHeOpLNlvMiiXM73Rmh8iBK1ZFLFd47kycYqIMq3Fm49ryAGUt79BXVPDyEB1IU3W0fgiL49iqTAVrpRszL10mmxzq_AQTJZVrXor-vne2w) 图标上,以便验证是否已针对您的项目启用测试。

2zbfeYpG-wEd2SFP07Wc4mJzHakLX7YvrNw3IV0_0Kd-TonfsKIvvjKWlwvrmTm5jLj3XPWqCtcDd5J2z6gwn9fnchpYVraw1j_mE4M0LVppAl5WY5cK7g0uZyhZ3VFFS25yPmyksg

现在,您可以开始实现必要的网络钩子,以便将设备状态关联到 Google 助理。

Action 配置完毕后,您就可以添加设备并发送数据了。您的云服务需要处理以下 intent:

  • 当 Google 助理想要了解用户关联了哪些设备时,就会发生 SYNC intent。当用户关联帐号时,系统会向您的服务发送此 intent。您应该在响应时提供所有用户设备及其功能的 JSON 载荷。
  • 当 Google 助理想要了解设备的当前状态时,就会发生 QUERY intent。您应该在响应时提供 JSON 载荷,其中包含所请求的每台设备的状态。
  • 当 Google 助理想要代表用户控制设备时,就会发生 EXECUTE intent。您应该在响应时提供 JSON 载荷,其中包含所请求的每台设备的执行状态。
  • 当用户将帐号与 Google 助理解除关联时,就会发生 DISCONNECT intent。您应该停止向 Google 助理发送此用户设备的相关事件。

您将在后面几个部分中更新之前部署的用于处理这些 intent 的函数。

更新 SYNC 响应

打开 functions/index.js,其中包含用于响应来自 Google 助理的请求的代码。

您需要通过返回设备元数据和功能来处理 SYNC intent。更新 onSync 数组中的 JSON,以便包含洗衣机的设备信息和推荐特征

index.js

app.onSync((body) => {
  return {
    requestId: body.requestId,
    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',
        ],
        name: {
          defaultNames: ['My Washer'],
          name: 'Washer',
          nicknames: ['Washer'],
        },
        deviceInfo: {
          manufacturer: 'Acme Co',
          model: 'acme-washer',
          hwVersion: '1.0',
          swVersion: '1.0.1',
        },
        willReportState: true,
        attributes: {
          pausable: true,
        },
      }],
    },
  };
});

部署到 Firebase

使用 Firebase CLI 部署更新后的云执行方式:

firebase deploy --only functions

为了测试您的智能家居 Action,您需要将项目与 Google 帐号相关联。这样一来,您就可以使用登录同一帐号的 Google 助理界面和 Google Home 应用来进行测试。

  1. 在手机上打开 Google 助理设置。请注意,您登录的帐号应该与控制台所用的帐号相同。
  2. 依次转到 Google 助理 > 设置 > 家居控制(位于“Google 助理”下方)。
  3. 点击右下角的加号 (+) 图标
  4. 您应该会看到带有 [test] 前缀及您设置的显示名的测试应用。
  5. 选择此项目。然后,Google 助理会通过您的服务进行身份验证并发送 SYNC 请求,以要求您的服务提供用户设备列表。

打开 Google Home 应用,然后验证您能否看到相应洗衣机设备。

XcWmBVamBZtPfOFqtsr5I38stPWTqDcMfQwbBjetBgxt0FCjEs285pa9K3QXSASptw0KYN2G8yfkT0-xg664V4PjqMreDDs-HPegHjOc4EVtReYPu-WKZyygq9Xmkf8X8z9177nBjQ

您的云服务可以向 Google 正确报告洗衣机设备后,您需要添加用于请求设备状态和发送命令的功能。

处理 QUERY intent

QUERY intent 包含一组设备。对于每种设备,您应该在响应时提供其当前状态。

functions/index.js 中,修改 QUERY 处理程序,以处理 intent 请求中包含的目标设备列表。

index.js

app.onQuery(async (body) => {
  const {requestId} = body;
  const payload = {
    devices: {},
  };
  const queryPromises = [];
  const intent = body.inputs[0];
  for (const device of intent.payload.devices) {
    const deviceId = device.id;
    queryPromises.push(queryDevice(deviceId)
        .then((data) => {
        // Add response to device payload
          payload.devices[deviceId] = data;
        }
        ));
  }
  // Wait for all promises to resolve
  await Promise.all(queryPromises);
  return {
    requestId: requestId,
    payload: payload,
  };
});

针对请求中包含的每台设备,返回 Realtime Database 中存储的当前状态。更新 queryFirebasequeryDevice 函数,以返回洗衣机的状态数据。

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

const queryDevice = async (deviceId) => {
  const data = await queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{
      currentCycle: 'rinse',
      nextCycle: 'spin',
      lang: 'en',
    }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
  };
};

处理 EXECUTE intent

EXECUTE intent 可处理用于更新设备状态的命令。响应会返回每个命令的状态(例如 SUCCESSERRORPENDING)以及新的设备状态。

functions/index.js 中,修改 EXECUTE 处理程序,以处理需要更新的特征列表以及每个命令的目标设备集:

index.js

app.onExecute(async (body) => {
  const {requestId} = body;
  // Execution results are grouped by status
  const result = {
    ids: [],
    status: 'SUCCESS',
    states: {
      online: true,
    },
  };

  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) => {
                  result.ids.push(device.id);
                  Object.assign(result.states, data);
                })
                .catch(() => functions.logger.error('EXECUTE', device.id)));
      }
    }
  }

  await Promise.all(executePromises);
  return {
    requestId: requestId,
    payload: {
      commands: [result],
    },
  };
});

针对每个命令和目标设备,更新 Realtime Database 中与所请求的特征相对应的值。修改 updateDevice 函数,以更新相应的 Firebase 引用并返回更新后的设备状态。

index.js

const updateDevice = async (execution, deviceId) => {
  const {params, command} = execution;
  let state; let 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;
  }

  return ref.update(state)
      .then(() => state);
};

三个 intent 全部实现后,您可以测试 Action 是否能够控制洗衣机。

部署到 Firebase

使用 Firebase CLI 部署更新后的云执行方式:

firebase deploy --only functions

测试洗衣机

现在,如果您通过手机尝试下达以下任意一条语音指令,就会看到值发生变化:

“Ok Google,启动洗衣机。”

“Ok Google,让洗衣机暂停运行。”

“Ok Google,让洗衣机停止运行。”

您还可以通过提问来查询洗衣机的当前状态。

“Ok Google,我的洗衣机启动了吗?”

“Ok Google,我的洗衣机在运行吗?”

“Ok Google,我的洗衣机洗到哪一步了?”

您还可以在 Firebase 控制台日志中查看这些查询和命令,具体方法是在导航菜单中依次点击开发 > 函数 > 日志

ce02fb66fe2037dc.png

您已将云服务与智能家居 intent 完全集成,让用户能够控制和查询设备的当前状态。不过,此实现仍缺少让您的服务能够主动向 Google 助理发送事件信息(例如,设备使用状态或状态的更改)的方法。

借助请求同步功能,您可以在用户添加或移除设备后,或在用户设备功能更改后触发新的同步请求。借助报告状态功能,在用户手动更改设备状态(例如,打开灯的开关)或使用其他服务更改状态后,您的云服务可以主动向 Home Graph 发送设备状态。

在此部分中,您将添加代码以从前端 Web 应用调用这些方法。

启用 HomeGraph API

借助 HomeGraph API,您可以在用户 Home Graph 中存储并查询设备及其状态。如需使用此 API,您必须先打开 Google Cloud Console,然后启用 HomeGraph API

在 Google Cloud Console 中,请务必选择与您的 Actions <project-id>. 相匹配的项目。然后,在 HomeGraph API 的 API 库屏幕中,点击启用

5SVCzM8IZLi_9DV8M0nEklv16NXkpvM0bIzQK2hSyKyvnFHBxPOz90rbr72ayxzmxd5aNROOqC_Cp4outbdlwJdObDs0DIE_8vYzw6dovoVrP9IZWlWsZxDS7UHOi1jiRbDMG8MqUA

启用报告状态

对 Realtime Database 的写入操作会触发入门级项目中的 reportstate 函数。更新 functions/index.js 中的 reportstate 函数,以捕获向数据库写入的数据,并通过状态报告将其发布到 Home Graph。

index.js

exports.reportstate = functions.database.ref('{deviceId}').onWrite(
    async (change, context) => {
      functions.logger.info('Firebase write event triggered Report State');
      const snapshot = change.after.val();

      const requestBody = {
        requestId: 'ff36a3cc', /* Any unique ID */
        agentUserId: USER_ID,
        payload: {
          devices: {
            states: {
              /* Report the current state of our washer */
              [context.params.deviceId]: {
                on: snapshot.OnOff.on,
                isPaused: snapshot.StartStop.isPaused,
                isRunning: snapshot.StartStop.isRunning,
              },
            },
          },
        },
      };

      const res = await homegraph.devices.reportStateAndNotification({
        requestBody,
      });
      functions.logger.info('Report state response:', res.status, res.data);
    });

启用请求同步

刷新前端网络界面的图标会触发入门级项目中的 requestsync 函数。在 functions/index.js 中实现 requestsync 函数,以调用 HomeGraph API。

index.js

exports.requestsync = functions.https.onRequest(async (request, response) => {
  response.set('Access-Control-Allow-Origin', '*');
  functions.logger.info(`Request SYNC for user ${USER_ID}`);
  try {
    const res = await homegraph.devices.requestSync({
      requestBody: {
        agentUserId: USER_ID,
      },
    });
    functions.logger.info('Request sync response:', res.status, res.data);
    response.json(res.data);
  } catch (err) {
    functions.logger.error(err);
    response.status(500).send(`Error requesting sync: ${err}`);
  }
});

部署到 Firebase

使用 Firebase CLI 部署更新后的代码:

firebase deploy --only functions

测试实现效果

点击网络界面中的刷新 ae8d3b25777a5e30.png 按钮,并验证能否在 Firebase 控制台日志中看到同步请求。

5241d663238a8d04.png

接下来,调整前端网络界面中的洗衣机设备属性,然后点击更新。验证能否在 Firebase 控制台日志中看到向 Google 报告的状态更改。

674c4f4392e98c1.png

恭喜!您已成功使用智能家居 Action 将 Google 助理与设备云服务集成。

了解详情

您可以实现以下想法以进行更深入的研究:

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