Conectar dispositivos de casa inteligente ao Google Assistente

Como desenvolvedor da Internet das Coisas (IoT, na sigla em inglês), é possível criar ações de casa inteligente que permitem os usuários controlar os dispositivos por meio dos controles por toque no app Google Home e nos comandos de voz com o Google Assistente.

79266e5f45e6ae20.gif

Essas ações usam o Home Graph para fornecer dados de contexto sobre a casa e os dispositivos, criando um mapa lógico da casa. Esse contexto permite que o Google Assistente entenda melhor as solicitações do usuário em relação à localização na casa. Por exemplo, o Home Graph pode armazenar o conceito de uma sala de estar que contém vários tipos de dispositivos de diferentes fabricantes, como termostato, luminária, ventilador e aspirador.

d009cef0f903d284.jpeg

Pré-requisitos

O que você criará

Neste codelab, você vai publicar um serviço de nuvem que gerencia uma máquina de lavar virtual, criar uma ação de casa inteligente e conectá-la ao Google Assistente.

O que você aprenderá

  • Como implantar um serviço de casa inteligente em nuvem
  • Como conectar seu serviço ao Google Assistente
  • Como publicar alterações de estado do dispositivo no Google

Pré-requisitos

Ativar os Controles de atividade

Ative os seguintes Controles de atividade na Conta do Google que você quer usar com o Google Assistente:

  • "Atividade na Web e de apps".
  • Informações do dispositivo
  • Atividade de voz e áudio

Criar um projeto do Actions

  1. Acesse o console para desenvolvedores do Actions on Google.
  2. Clique em Novo projeto, insira um nome e clique em CRIAR PROJETO.

AWXw5E1m9zVgvVeyeL3uxwCX6DtWOCK6LRSLmOATFzjMbmE5cSWBdSVhJZDFpEFH2azZTK2eMs6OYYdMJYiGb5bKqFEzxaLyRUYuwVGBlSjXzTyy8Z9CvwpXvRwP7xdycklETzFc7Q

Selecione o app casa inteligente

Na tela Visão geral do Console do Actions, selecione Casa inteligente.

36RsBUWBgbgsa5xZ7MJVMm1sIg07nXbfjv0mWCxXViaC5SlbL2gMigw9hgXsZQhNMHLLFOfiKdZsSTNXONFB1i47gksw3SBNpkVYl492WeryOlgxKjpVrLAvg-5cZqu1DI-s5kxM3g

Escolha o card de experiência casa inteligente para acessar o console do projeto.

pzgHPsmc2LvLoeUvJfkjKQqD_BvO4v8JOPlcrxsmyptFkkjL4PP6LqrM9r5tNvEIfT9HmK-UKw3GWFPXTjqo4nUrhD2o5shUKHBE31OT8iIA69JZCev7_0_nh-lnL2oJHoxGfqqZ4w

Instalar a CLI do Firebase

A interface de linha de comando (CLI, na sigla em inglês) do Firebase permite exibir seus apps da Web localmente e implantá-los no Firebase Hosting.

Para instalar a CLI, execute o seguinte comando NPM no terminal:

npm install -g firebase-tools

Para verificar se a CLI foi instalada corretamente, execute o seguinte:

firebase --version

Autorize a CLI do Firebase com sua Conta do Google. Para isso, execute o seguinte:

firebase login

Após configurar o ambiente para desenvolvedores, implante o projeto inicial para verificar se a configuração está correta.

Faça o download do código-fonte

Clique neste link para fazer o download do exemplo deste codelab na máquina de desenvolvimento:

Faça o download do código-fonte

…ou clone o repositório do GitHub da linha de comando:

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

Sobre o projeto

O projeto inicial contém os seguintes subdiretórios:

  • public: Uma IU de front-end para controlar e monitorar o estado da lavadora inteligente.
  • functions: Um serviço de nuvem totalmente implementado que gerencia a lavadora inteligente com o Cloud Functions para Firebase e o Firebase Realtime Database.

Conectar-se ao Firebase

Acesse o diretório washer-start e configure a CLI do Firebase com seu projeto do Actions:

cd washer-start
firebase use <project-id>

Implantar no Firebase

Acesse a pasta functions e instale todas as dependências necessárias usando npm..

cd functions
npm install

Após instalar as dependências e configurar o projeto, você já pode executar o app pela primeira vez.

firebase deploy

Esta é a resposta do console que deverá aparecer:

...

✔ Deploy complete!

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

Esse comando implanta um app da Web, além de várias Cloud Functions para Firebase.

Abra o URL de hospedagem no navegador (https://<project-id>.firebaseapp.com) para ver o app da Web. Aparecerá a seguinte interface:

L60eA7MOnPmbBMl2XMipT9MdnP-RaVjyjf0Y93Y1b7mEyIsqZrrwczE7D3RQISRs-iusL1g4XbNmGhuA6-5sLcWefnczwNJEPfNLtwBsO4Tb9YvcAZBI6_rX19z8rxbik9Vq8F2fwg

Essa IU da Web representa uma plataforma de terceiros para exibir ou modificar estados do dispositivo. Para começar a preencher seu banco de dados com informações do dispositivo, clique em ATUALIZAR. Você não verá mudanças na página, mas o estado atual da lavadora será armazenado no banco de dados.

Agora, conecte o serviço em nuvem que você implantou ao Google Assistente usando o Console do Actions.

Configurar seu projeto do console do Actions

Em Visão geral > Criar sua ação, selecione Adicionar ações. Insira o URL da função do Cloud que oferece fulfillment para as intents de casa inteligente e clique em Salvar.

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

Uso-o00XQXBHvOR9vQq9tmpYDYQJKsFEstsgRFnxPAJf7zJ2FxwhISiodo3dB1Tz49Okd6ivi66fjpo7rarS_GZelglGWCT1r9FzDGUl1r67ddIcIbQrxqN8jG9F9GAKOpk0Ckc-eA

Na guia Desenvolver > Invocação, adicione um nome de exibição para a ação e clique em Salvar. Esse nome aparecerá no app Google Home.

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

s4yc1kOW4XtKUQN1EYegiDLU5oTqmxQ2PNbeaujm26OQmYKKpjug7j5FYmutLSAZ1zBd-ZkcZlL7zyTZqw4bge3_oOeWvJTsqJ-A08vfZwImYQrKiquLskLuTpmMqXEZD1xchhCWGQ

Para ativar a vinculação de contas, selecione a opção Desenvolver > Vinculação de contas na navegação à esquerda. Use estas configurações de vinculação de conta:

ID do cliente

ABC123

Chave secreta do cliente

DEF456

URL de autorização

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

URL do token

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

rRyZTiBSTuPk3YtJtXjDK1pPftUxsaEhs9jzpvFtbHTD6bEwYxM8jV4MWxiljKA1bKVZrIRoO9O3jtBefLKf_OyMpukPjwIj8zGvyU3UwASzMrnRskl-hVAfAmQVi4sC_zAwgYwRXw

Clique em Salvar para armazenar a configuração de vinculação da conta e, depois, em Testar para ativar o teste no seu projeto.

OgUvpQfXioygkRwPcaJpzjyNQDZy6enidUC8YMPaCOrZi0YeWCFsCJV9Gqg-_UfsqTnn4KEg--uE3Ymr0QuamDonF4RyYHtRKcULXABDuaEnj2hq8i20LYj1SrGP_1lQ_UsUB90pGw

Sua tela será redirecionada para o simulador. Para verificar se o teste foi ativado para o projeto, mova o mouse sobre o ícone Teste em dispositivo ( soCeBB1CkSIEqsBmDc8Cth6EjgcXUnrOHeOpLNlvMiiXM73Rmh8iBK1ZFLFd47kycYqIMq3Fm49ryAGUt79BXVPDyEB1IU3W0fgiL49iqTAVrpRszL10mmxzq_AQTJZVrXor-vne2w).

2zbfeYpG-wEd2SFP07Wc4mJzHakLX7YvrNw3IV0_0Kd-TonfsKIvvjKWlwvrmTm5jLj3XPWqCtcDd5J2z6gwn9fnchpYVraw1j_mE4M0LVppAl5WY5cK7g0uZyhZ3VFFS25yPmyksg

Agora, você pode começar a implementar os webhooks necessários para conectar o estado do dispositivo ao Google Assistente.

Após configurar a ação, você poderá adicionar dispositivos e enviar dados. Seu serviço em nuvem precisa processar as seguintes intents:

  • A intent SYNC ocorre quando o Google Assistente quer saber a quais dispositivos o usuário está conectado. Ela é enviada ao seu serviço quando o usuário vincula uma conta. Você deve responder com um payload JSON de todos os dispositivos e recursos do usuário.
  • A intent QUERY ocorre quando o Google Assistente quer saber o estado atual ou o status de um dispositivo. Você deve responder com um payload JSON com o estado de cada dispositivo solicitado.
  • A intent EXECUTE ocorre quando o Google Assistente quer controlar um dispositivo em nome do usuário. Você deve responder com um payload JSON com o status de execução de cada dispositivo solicitado.
  • A intent DISCONNECT ocorre quando o usuário desvincula a conta do Google Assistente. Você deve parar de enviar eventos dos dispositivos deste usuário para o Google Assistente.

Você atualizará as funções implantadas para manipular as intents nas seções a seguir.

Atualizar resposta sincronizada

Abra functions/index.js, que contém o código para responder a solicitações do Google Assistente.

Você precisará processar uma intent SYNC. Para isso, retorne os metadados e os recursos do dispositivo. Atualize o JSON na matriz onSync para incluir as informações do dispositivo e os traços recomendados para uma lavadora de roupas.

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

Implantar no Firebase

Implante o fulfillment da nuvem atualizado usando a CLI do Firebase:

firebase deploy --only functions

Para testar a ação da casa inteligente, você precisa vincular seu projeto a uma Conta do Google. Isso permite realizar testes usando as plataformas do Google Assistente e o app Google Home, desde que estejam conectados à mesma conta.

  1. No smartphone, abra as configurações do Google Assistente. Você precisa fazer login na mesma conta que no console.
  2. Acesse Google Assistente > Configurações > Automação residencial (em Google Assistente).
  3. Selecione o ícone de adição (+) no canto inferior direito
  4. Você verá o app de teste com o prefixo [test] e o nome de exibição que você definiu.
  5. Selecione esse item. O Google Assistente será autenticado com seu serviço e enviará uma solicitação SYNC para que o serviço forneça uma lista de dispositivos para o usuário.

Abra o app Google Home e verifique se aparece o dispositivo da lavadora.

XcWmBVamBZtPfOFqtsr5I38stPWTqDcMfQwbBjetBgxt0FCjEs285pa9K3QXSASptw0KYN2G8yfkT0-xg664V4PjqMreDDs-HPegHjOc4EVtReYPu-WKZyygq9Xmkf8X8z9177nBjQ

Agora que seu serviço de nuvem informa corretamente o dispositivo da lavadora ao Google, adicione o recurso para solicitar o estado do dispositivo e enviar comandos.

Processar intents de CONSULTA

Uma intent QUERY inclui um conjunto de dispositivos. Você deve responder com o estado atual de cada dispositivo.

Em functions/index.js, edite o gerenciador QUERY para processar a lista de dispositivos de destino na solicitação de 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,
  };
});

Retorne o estado atual armazenado no Realtime Database de cada dispositivo da solicitação. Atualize as funções queryFirebase e queryDevice para retornar os dados de estado da lavadora.

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

Processar intents de EXECUÇÃO

A intent EXECUTE processa comandos para atualizar o estado do dispositivo. A resposta retorna o status de cada comando, como SUCCESS, ERROR ou PENDING, e o novo estado do dispositivo.

Em functions/index.js, edite o gerenciador EXECUTE para processar a lista de traços que precisam de atualizações e o conjunto de dispositivos de destino de cada comando:

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

Atualize os valores no Realtime Database que correspondem ao traço solicitado de cada comando e dispositivo de destino. Modifique a função updateDevice para atualizar a referência apropriada do Firebase e retornar o estado atualizado do dispositivo.

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

Depois de implementar as três intents, é possível testar se a ação controla a lavadora.

Implantar no Firebase

Implante o fulfillment da nuvem atualizado usando a CLI do Firebase:

firebase deploy --only functions

Testar a lavadora

Agora você pode ver a mudança no valor ao tentar usar um dos seguintes comandos de voz no seu smartphone:

"Ok Google, ligar minha lavadora."

"Ok Google, pausar minha lavadora."

"Ok Google, parar minha lavadora."

Também é possível fazer perguntas para ver o estado atual da sua lavadora.

"Ok Google, minha lavadora está ligada?"

"Ok Google, minha lavadora está funcionando?"

"Ok Google, em que ciclo está a lavadora?"

Você também pode ver essas consultas e comandos nos registros do Console do Firebase. Basta clicar em Desenvolver > Funções > Registros no menu de navegação.

ce02fb66fe2037dc.png

Você integrou totalmente seu serviço de nuvem com as intents de casa inteligente. Assim, os usuários podem controlar e conferir o estado atual dos dispositivos. No entanto, a implementação ainda não permite que o serviço envie informações do evento (como alterações de estado ou presença do dispositivo) para o Google Assistente por conta própria.

Com a sincronização de solicitações, você pode acionar uma nova solicitação de sincronização quando os usuários adicionarem ou removerem dispositivos ou quando os recursos do dispositivo mudarem. Com o Estado do relatório, o serviço de nuvem pode enviar o estado de um dispositivo para o Home Graph por conta própria quando os usuários mudarem fisicamente o estado de um dispositivo (por exemplo, ao acender uma luz) ou mudarem o estado usando outro serviço.

Nesta seção, você vai adicionar código para chamar esses métodos do app da Web de front-end.

Ativar a API HomeGraph

A API HomeGraph permite armazenar e consultar dispositivos e os estados deles no Home Graph de um usuário. Para usar essa API, primeiro abra o Console do Google Cloud e ative a API HomeGraph.

Nesse console, selecione o projeto que corresponde às ações <project-id>.. Em seguida, na API HomeGraph da tela da biblioteca, clique em Ativar.

5SVCzM8IZLi_9DV8M0nEklv16NXkpvM0bIzQK2hSyKyvnFHBxPOz90rbr72ayxzmxd5aNROOqC_Cp4outbdlwJdObDs0DIE_8vYzw6dovoVrP9IZWlWsZxDS7UHOi1jiRbDMG8MqUA

Ativar estado do relatório

As gravações no Realtime Database acionam a função reportstate no projeto inicial. Atualize a função reportstate em functions/index.js para capturar os dados gravados no banco de dados e postá-los no Home Graph usando o estado do relatório.

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

Ativar a sincronização de solicitações

A atualização do ícone na IU da Web do front-end aciona a função requestsync no projeto inicial. Implemente a função requestsync em functions/index.js para chamar a 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}`);
  }
});

Implantar no Firebase

Implante o código atualizado usando a CLI do Firebase:

firebase deploy --only functions

Como testar a implementação

Clique no botão Atualizar ae8d3b25777a5e30.png na IU da Web e verifique se aparece uma solicitação de sincronização no registro do Console do Firebase.

5241d663238a8d04.png

Em seguida, ajuste os atributos do dispositivo da lavadora na IU da Web do front-end e clique em Atualizar. Verifique se é possível ver a alteração de estado informada para o Google nos registros do console do Firebase.

674c4f4392e98c1.png

Parabéns! Você integrou o Google Assistente a um serviço de nuvem do dispositivo usando ações de casa inteligente.

Saiba mais

Veja algumas ideias que você pode implementar para ir mais a fundo:

Você também pode saber mais sobre como testar e enviar uma ação para análise, incluindo o processo de certificação para publicá-la aos usuários.