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

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

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

79266e5f45e6ae20.gif

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

d009cef0f903d284.jpeg

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

Что вы построите

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

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

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

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

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

Включить элементы управления активностью

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

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

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

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

Создайте проект интеграции между облачными сервисами.

  1. Перейдите в консоль разработчика .
  2. Нажмите «Создать проект» , введите название проекта и нажмите «Создать проект» .

Название проекта

Выберите интеграцию «облако-облако».

На главной странице проекта в консоли разработчика выберите пункт «Добавить интеграцию между облаками» в разделе «Интеграция между облаками» .

Добавьте интеграцию между облачными сервисами.

Установите Firebase CLI.

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

Для установки CLI выполните следующую команду npm в терминале:

npm install -g firebase-tools

Чтобы убедиться в правильности установки интерфейса командной строки, выполните следующую команду:

firebase --version

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

firebase login

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

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

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

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

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

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

О проекте

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

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

Добавьте Firebase в свой проект в консоли разработчика Google Home.

Способ 1: Через консоль Firebase

  1. Перейдите на сайт Firebase .
  2. Нажмите «Создать проект Firebase» .
    Создать проект Firebase
  3. На экране «Создать проект» нажмите «Добавить проект Firebase в Google Cloud» .
    Добавить Firebase в проект Google Cloud
  4. На экране «Начало работы» выберите проект Google Cloud, который вы только что создали в консоли разработчика Google Home, а затем нажмите «Продолжить» .
    Выберите проект Google Cloud

Метод 2: Через интерфейс командной строки Firebase

firebase projects:addfirebase

Выберите проект Google Home Developer Console, который вы только что создали, чтобы добавить Firebase.

После добавления Firebase в ваш проект в консоли разработчика Google Home, он отобразится в консоли Firebase. Идентификатор проекта Firebase будет совпадать с идентификатором вашего проекта в консоли разработчика Google Home.

Добавлен облачный проект.

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

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

cd washer-start
firebase use <project-id>

Настройка проекта Firebase

Инициализируйте проект Firebase.

firebase init

Выберите функции командной строки, базу данных реального времени и функцию «Функции» .

? 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.

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

Если ESLint был случайно включен, есть два способа его отключить:

  1. С помощью графического интерфейса перейдите в папку ../functions внутри проекта, выберите скрытый файл .eslintrc.js и удалите его. Не путайте его с файлом .eslintrc.json имеющим аналогичное имя.
  2. Использование командной строки:
    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

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

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

5845443e94705557.png

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

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

Настройте свой проект в консоли разработчика.

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

Добавить отображаемое имя

В разделе «Брендинг приложения» загрузите файл png для значка приложения размером 144 x 144 пикселя и назовите его соответствующим образом. .png .

Добавить значок приложения

Для включения функции привязки учетных записей используйте следующие настройки привязки учетных записей:

Идентификатор клиента

ABC123

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

DEF456

URL авторизации

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

URL токена

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

Обновите URL-адреса для привязки учетных записей.

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

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

Добавить URL-адрес облачной функции

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

Протестируйте интеграцию между облачными сервисами.

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

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 CLI:

firebase deploy --only functions

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

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

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

ae252220753726f6.png

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

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

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

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

В 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. Обновите функции queryFirebase и queryDevice , чтобы они возвращали данные о состоянии стиральной машины.

index.js

const queryFirebase = async (deviceId) => {
  const snapshot = await getFirebaseRef().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 обрабатывает команды для обновления состояния устройства. В ответ возвращается статус каждой команды — например, 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 = getFirebaseRef().child(deviceId).child('OnOff');
      break;
    case 'action.devices.commands.StartStop':
      state = params.start
      ? {isRunning: true, isPaused: false}
      : {isRunning: false, isPaused: false};
      ref = getFirebaseRef().child(deviceId).child('StartStop');
      break;
    case 'action.devices.commands.PauseUnpause':
      const data = await queryDevice(deviceId);
      state = (data.isPaused === false && data.isRunning === false)
        ? {isRunning: false, isPaused: false}
        : {isRunning: !params.pause, isPaused: params.pause};
      ref = getFirebaseRef().child(deviceId).child('StartStop');
      break;
  }

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

6. Протестируйте интеграцию.

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

Развернуть в Firebase

Разверните обновленную облачную среду выполнения с помощью Firebase CLI:

firebase deploy --only functions

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

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

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

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

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

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

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

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

"Привет, Google, какой режим стирки у меня включен?"

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

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

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

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

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

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

Включите API HomeGraph

API HomeGraph позволяет хранить и запрашивать информацию об устройствах и их состояниях в рамках пользовательского HomeGraph. Для использования этого API необходимо сначала открыть консоль Google Cloud и включить API HomeGraph .

В консоли 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 отображается запрос на синхронизацию.

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

8. Поздравляем!

674c4f4392e98c1.png

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

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

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

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