Подключите устройства умного дома к Google Ассистенту

1. Прежде чем начать

Как разработчик Интернета вещей (IoT), вы можете создавать действия для умного дома , которые дают вашим пользователям возможность управлять своими устройствами с помощью сенсорного управления в приложении Google Home и голосовых команд с помощью Ассистента.

79266e5f45e6ae20.gif

Действия умного дома полагаются на Home Graph для предоставления контекстных данных о доме и его устройствах, создавая логическую карту дома. Этот контекст дает Помощнику более естественное понимание запросов пользователя относительно его местоположения в доме. Например, Home Graph может хранить концепцию гостиной, в которой есть несколько типов устройств разных производителей, таких как термостат, лампа, вентилятор и пылесос.

d009cef0f903d284.jpeg

Предварительные условия

Что ты построишь

В этой лаборатории кода вы опубликуете облачный сервис, который управляет виртуальной интеллектуальной стиральной машиной, затем создадите действие «умный дом» и подключите его к Помощнику.

Что вы узнаете

  • Как развернуть облачный сервис умного дома
  • Как подключить свой сервис к Ассистенту
  • Как опубликовать изменения состояния устройства в Google

Что вам понадобится

2. Начало работы

Включить контроль активности

Чтобы использовать Google Assistant, вы должны предоставить Google определенные данные о деятельности. Google Assistant нужны эти данные для правильной работы; однако требование обмена данными не является специфичным для SDK. Чтобы поделиться этими данными, создайте учетную запись Google, если у вас ее еще нет. Вы можете использовать любую учетную запись Google — это не обязательно должна быть ваша учетная запись разработчика.

Откройте страницу «Контроль активности» для учетной записи Google, которую вы хотите использовать с Ассистентом.

Убедитесь, что следующие тумблеры включены:

  • Активность в Интернете и приложениях . Кроме того, обязательно установите флажок Включать историю и активность Chrome на сайтах, приложениях и устройствах, использующих службы Google .
  • Информация об устройстве
  • Голосовая и аудио активность

Создать проект действий

  1. Перейдите в Действия в консоли разработчика Google .
  2. Нажмите «Новый проект» , введите имя проекта и нажмите «СОЗДАТЬ ПРОЕКТ» .

3d6b68ca79afd54c.png

Выберите приложение «Умный дом».

На экране «Обзор» в консоли «Действия» выберите «Умный дом» .

2fa4988f44f8914b.png

Выберите карточку «Умный дом» , нажмите «Начать сборку» , и вы будете перенаправлены на консоль вашего проекта.

Установите интерфейс командной строки Firebase

Интерфейс командной строки Firebase (CLI) позволит вам обслуживать ваши веб-приложения локально и развертывать их на хостинге Firebase.

Чтобы установить CLI, выполните следующую команду npm из терминала:

npm install -g firebase-tools

Чтобы убедиться, что CLI установлен правильно, запустите:

firebase --version

Авторизуйте Firebase CLI с помощью своей учетной записи Google, выполнив:

firebase login

3. Запустите стартовое приложение.

Теперь, когда вы настроили среду разработки, вы можете развернуть стартовый проект, чтобы убедиться, что все настроено правильно.

Получить исходный код

Щелкните следующую ссылку, чтобы загрузить образец этой лаборатории кода на свою машину разработки:

…или вы можете клонировать репозиторий GitHub из командной строки:

git clone https://github.com/google-home/smarthome-washer.git

О проекте

Стартовый проект содержит следующие подкаталоги:

  • public: интерфейсный интерфейс, позволяющий легко управлять и отслеживать состояние умной стиральной машины.
  • functions: полностью реализованный облачный сервис, который управляет интеллектуальной стиральной машиной с помощью облачных функций для Firebase и базы данных Firebase Realtime.

Подключиться к Firebase

Перейдите в каталог washer-start , затем настройте интерфейс командной строки Firebase для вашего проекта Actions:

cd washer-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

Если вы повторно инициализируете свой проект, выберите «Нет» , когда вас спросят, хотите ли вы инициализировать или перезаписать function/.gitignore.

? File functions/.gitignore already exists. Overwrite?
No
? Do you want to install dependencies with npm now?
Yes

Наконец, настройте хостинг для использования 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 был случайно включен, его можно отключить двумя способами:

  1. Используя графический интерфейс, перейдите в папку ../functions проекта, выберите скрытый файл .eslintrc.js и удалите его. Не путайте его с одноименным .eslintrc.json .
  2. Используя командную строку:
    cd functions
    rm .eslintrc.js
    

Чтобы убедиться, что у вас правильная и полная конфигурация Firebase, скопируйте файл firebase.json из каталога app-done в каталог app-start , перезаписав файл в app-start .

В каталоге app-start :

cp -vp ../app-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

Эта команда развертывает веб-приложение вместе с несколькими облачными функциями для Firebase .

Откройте URL-адрес хостинга в своем браузере ( https://<project-id>.web.app ), чтобы просмотреть веб-приложение. Вы увидите следующий интерфейс:

5845443e94705557.png

Этот веб-интерфейс представляет собой стороннюю платформу для просмотра или изменения состояний устройства. Чтобы начать заполнять базу данных информацией об устройстве, нажмите «ОБНОВИТЬ» . На странице вы не увидите никаких изменений, но текущее состояние вашей стиральной машины будет сохранено в базе данных.

Теперь пришло время подключить развернутый вами облачный сервис к Google Assistant с помощью консоли Actions .

Настройте проект консоли Actions

В разделе «Обзор» > «Создайте свое действие» выберите «Добавить действия» . Введите URL-адрес своей облачной функции, обеспечивающей реализацию намерений умного дома, и нажмите «Сохранить» .

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

9d7b223427f587ca.png

На вкладке «Разработка» > «Вызов» добавьте отображаемое имя для своего действия и нажмите «Сохранить» . Это имя появится в приложении Google Home.

774d0c40c351c7da.png

a8c4673eb11d76ee.png

Чтобы включить привязку учетной записи, выберите параметр «Разработка» > «Привязка учетной записи» на левой панели навигации. Используйте следующие настройки привязки учетной записи:

ID клиента

ABC123

Секрет клиента

DEF456

URL-адрес авторизации

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

URL-адрес токена

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

9730d20b90bcc038.png

Нажмите «Сохранить» , чтобы сохранить конфигурацию привязки вашей учетной записи, затем нажмите «Тест» , чтобы включить тестирование в вашем проекте.

ee0547f05b5efd98.png

Вы будете перенаправлены в Симулятор . Если вы не видите сообщение « Тест теперь включен », нажмите «Сбросить тест» , чтобы убедиться, что тестирование включено.

d0495810dbadf059.png

Теперь вы можете приступить к реализации веб-перехватчиков, необходимых для связи состояния устройства с Ассистентом.

4. Создайте шайбу

Теперь, когда вы настроили свое действие, вы можете добавлять устройства и отправлять данные. Ваша облачная служба должна обрабатывать следующие цели:

  • Намерение SYNC возникает, когда Ассистент хочет знать, какие устройства подключил пользователь. Он отправляется в вашу службу, когда пользователь связывает учетную запись. Вы должны ответить, отправив в формате JSON данные обо всех устройствах пользователя и их возможностях.
  • Намерение QUERY возникает, когда Ассистент хочет узнать текущее состояние или статус устройства. Вы должны ответить с помощью полезных данных JSON с состоянием каждого запрошенного устройства.
  • Намерение EXECUTE возникает, когда Помощник хочет управлять устройством от имени пользователя. Вы должны ответить с помощью полезных данных JSON со статусом выполнения каждого запрошенного устройства.
  • Намерение DISCONNECT возникает, когда пользователь отключает связь своей учетной записи с Ассистентом. Вам следует прекратить отправлять события для устройств этого пользователя в Ассистент.

В следующих разделах вы обновите функции, которые вы ранее развернули для обработки этих намерений.

Обновить ответ SYNC

Откройте functions/index.js , который содержит код для ответа на запросы Ассистента.

Вам нужно будет обработать намерение SYNC , вернув метаданные и возможности устройства. Обновите JSON в массиве onSync , включив в него информацию об устройстве и рекомендуемые характеристики стиральной машины.

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:

firebase deploy --only functions

Чтобы протестировать действие вашего умного дома, вам необходимо связать свой проект с учетной записью Google. Это позволяет проводить тестирование через поверхности Google Assistant и приложение Google Home, которые вошли в одну и ту же учетную запись.

  1. На телефоне откройте настройки Google Assistant. Обратите внимание, что вы должны войти в систему под той же учетной записью, что и в консоли.
  2. Перейдите в «Google Ассистент» > «Настройки» > «Управление домом» (в разделе «Ассистент»).
  3. Нажмите значок поиска в правом верхнем углу.
  4. Найдите свое тестовое приложение, используя префикс [test] , чтобы найти конкретное тестовое приложение.
  5. Выберите этот элемент. Затем Google Assistant пройдет аутентификацию в вашей службе и отправит запрос SYNC , попросив вашу службу предоставить пользователю список устройств.

Откройте приложение Google Home и убедитесь, что вы видите стиральную машину.

ae252220753726f6.png

5. Обработка команд и запросов

Теперь, когда ваш облачный сервис правильно сообщает Google о стиральном устройстве, вам необходимо добавить возможность запрашивать состояние устройства и отправлять команды.

Обработка намерения QUERY

Намерение QUERY включает в себя набор устройств. Для каждого устройства вы должны ответить его текущим состоянием.

В functions/index.js отредактируйте обработчик QUERY , чтобы обработать список целевых устройств, содержащийся в запросе намерения.

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

Для каждого устройства, содержащегося в запросе, верните текущее состояние, хранящееся в базе данных реального времени. Обновите функции queryFirebase и queryDevice , чтобы они возвращали данные о состоянии стиральной машины.

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

Намерение EXECUTE обрабатывает команды для обновления состояния устройства. Ответ возвращает статус каждой команды — например, SUCCESS , ERROR или PENDING — и состояние нового устройства.

В 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],
    },
  };
});

Для каждой команды и целевого устройства обновите значения в базе данных реального времени, соответствующие запрошенному признаку. Измените функцию 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);
};

6. Проверьте свое действие

После реализации всех трех намерений вы можете проверить, что ваше действие управляет стиральной машиной.

Развертывание в Firebase

Разверните обновленное облачное выполнение с помощью интерфейса командной строки Firebase:

firebase deploy --only functions

Проверьте стиральную машину

Теперь вы можете увидеть изменение значения, когда попробуете любую из следующих голосовых команд через телефон:

«Эй, Google, включи мою стиральную машину».

«Окей, Google, приостанови мою стиральную машину».

«Эй, Google, останови мою стиральную машину».

Вы также можете увидеть текущее состояние вашей стиральной машины, задавая вопросы.

«Окей, Google, моя стиральная машина включена?»

«Окей, Google, моя стиральная машина работает?»

«Окей, Google, на каком цикле работает моя стиральная машина?»

Вы можете просмотреть эти запросы и команды в журналах, которые отображаются под вашей функцией в разделе «Функции» консоли Firebase . Узнайте больше о журналах Firebase в разделе «Запись и просмотр журналов» .

Вы также можете найти эти запросы и команды в Google Cloud Console , перейдя в раздел «Ведение журналов» > «Обозреватель журналов» . Узнайте больше о ведении журналов Google Cloud в статье Доступ к журналам событий с помощью Cloud Logging .

7. Сообщайте об обновлениях в Google.

Вы полностью интегрировали свой облачный сервис с функциями умного дома, что позволяет пользователям контролировать и запрашивать текущее состояние своих устройств. Однако в реализации по-прежнему отсутствует возможность для вашей службы заранее отправлять информацию о событиях, например изменения в присутствии или состоянии устройства, в Помощник.

С помощью Request Sync вы можете инициировать новый запрос на синхронизацию, когда пользователи добавляют или удаляют устройства или когда изменяются возможности их устройств. С помощью Report State ваша облачная служба может заранее отправлять состояние устройства в Home Graph, когда пользователи физически изменяют состояние устройства (например, включают выключатель света) или меняют состояние с помощью другой службы.

В этом разделе вы добавите код для вызова этих методов из внешнего веб-приложения.

Включите API HomeGraph

API HomeGraph позволяет хранить и запрашивать устройства и их состояния в Home Graph пользователя. Чтобы использовать этот API, необходимо сначала открыть консоль Google Cloud и включить HomeGraph API .

В консоли Google Cloud обязательно выберите проект, соответствующий вашим действиям <project-id>. Затем на экране библиотеки API для HomeGraph API нажмите «Включить» .

ee198858a6eac112.png

Включить состояние отчета

Запись в базу данных реального времени запускает функцию reportstate в стартовом проекте. Обновите функцию reportstate в functions/index.js , чтобы захватывать данные, записанные в базу данных, и публиковать их в Home Graph через Report State.

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 в стартовом проекте. Реализуйте функцию requestsync в functions/index.js для вызова API HomeGraph.

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.

Затем настройте атрибуты стирального устройства в интерфейсном веб-интерфейсе и нажмите «Обновить» . Убедитесь, что вы видите изменение состояния, о котором сообщается в Google, в журналах консоли Firebase.

8. Поздравления

674c4f4392e98c1.png

Поздравляем! Вы успешно интегрировали Помощника с облачной службой устройства с помощью действий умного дома.

Узнать больше

Вот несколько идей, которые вы можете реализовать, чтобы пойти глубже:

Вы также можете узнать больше о тестировании и отправке действия на рассмотрение, включая процесс сертификации для публикации вашего действия для пользователей.