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

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

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

79266e5f45e6ae20.gif

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

d009cef0f903d284.jpeg

Предпосылки

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

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

Чему вы научитесь

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

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

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

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

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

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

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

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

Создайте проект интеграции облака в облако

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

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

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

На главной странице проекта в консоли разработчика выберите Добавить интеграцию «облако-облако» в разделе «Облако-облако» .

Добавить интеграцию облако-облако

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

Интерфейс командной строки 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 в свой проект консоли разработчика 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 CLI

firebase projects:addfirebase

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

Когда Firebase будет добавлен в ваш проект Google Home Developer Console, он появится в Firebase Console. Идентификатор проекта Firebase будет соответствовать идентификатору вашего проекта Google Home Developer Console.

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

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

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

cd washer-start
firebase use <project-id>

Настроить проект Firebase

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

firebase init

Выберите функции CLI, Realtime Database и функцию Functions .

? 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. Используя GUI, перейдите в папку ../functions в проекте, выберите скрытый файл .eslintrc.js и удалите его. Не путайте его с файлом с похожим названием .eslintrc.json .
  2. Использование командной строки:
    cd functions
    rm .eslintrc.js
    

В файле washer-start/firebase.json дополните код следующим образом:

{
  "database": {
    "rules": "database.rules.json"
  },
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },
    "headers": [{
      "source" : "**/*.@(js|html)",
      "headers" : [ {
        "key" : "Cache-Control",
        "value" : "max-age=0"
      } ]
    }],
  "functions": [
    {
      "source": "functions",
      "codebase": "default",
      "ignore": [
        "node_modules",
        ".git",
        "firebase-debug.log",
        "firebase-debug.*.log",
        "*.local"
      ]
    }
  ]
}

Развертывание в 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 с помощью консоли разработчика Google Home .

Настройте свой проект Developer Console

На вкладке «Разработка» добавьте Отображаемое имя для вашего взаимодействия. Это имя будет отображаться в приложении 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 возникает, когда пользователь отвязывает свою учетную запись от Assistant. Вам следует прекратить отправлять события для устройств этого пользователя в Assistant.

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

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

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

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

индекс.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

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

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

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

ae252220753726f6.png

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

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

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

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

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

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

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

индекс.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 и вернуть обновленное состояние устройства.

индекс.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 = params.start
      ? {isRunning: true, isPaused: false}
      : {isRunning: false, isPaused: false};
      ref = firebaseRef.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 = firebaseRef.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 Console , перейдя в Logging > Logs Explorer . Узнайте больше о ведении журналов Google Cloud в разделе Журналы событий Access с Cloud Logging .

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

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

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

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

Включить API HomeGraph

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

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

ee198858a6eac112.png

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

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

индекс.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.

индекс.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

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

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

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

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