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.

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.

Pré-requisitos
- Guia do desenvolvedor: Criar uma ação de casa inteligente
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
- Um navegador da Web, como o Google Chrome
- Um dispositivo iOS ou Android com o app Google Home instalado
- Node.js versão 10.16 ou mais recente
- Uma conta de faturamento do Google Cloud
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
- Acesse o console para desenvolvedores do Actions on Google.
- Clique em Novo projeto, insira um nome e clique em CRIAR PROJETO.
Selecione o app casa inteligente
Na tela Visão geral do Console do Actions, selecione Casa inteligente.
Escolha o card de experiência casa inteligente para acessar o console do projeto.
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:
…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:
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
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.
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 | 
 | 
| Chave secreta do cliente | 
 | 
| URL de autorização | 
 | 
| URL do token | 
 | 
Clique em Salvar para armazenar a configuração de vinculação da conta e, depois, em Testar para ativar o teste no seu projeto.
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 (  ).
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 SYNCocorre 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 QUERYocorre 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 EXECUTEocorre 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 DISCONNECTocorre 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
Vincular ao Google Assistente
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.
- No smartphone, abra as configurações do Google Assistente. Você precisa fazer login na mesma conta que no console.
- Acesse Google Assistente > Configurações > Automação residencial (em Google Assistente).
- Selecione o ícone de adição (+) no canto inferior direito
- Você verá o app de teste com o prefixo [test] e o nome de exibição que você definiu.
- Selecione esse item. O Google Assistente será autenticado com seu serviço e enviará uma solicitação SYNCpara 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.
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.

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.
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   na IU da Web e verifique se aparece uma solicitação de sincronização no registro do Console do Firebase.
 na IU da Web e verifique se aparece uma solicitação de sincronização no registro do Console do Firebase.

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.

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:
- Adicione modos e botões ao seu dispositivo.
- Adicione mais traços compatíveis ao seu dispositivo.
- Conheça a execução local para casas inteligentes.
- Confira nosso exemplo do GitHub para ver mais informações.
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.