Melhorar e proteger suas integrações entre nuvens

1. Antes de começar

As integrações de nuvem para nuvem usam tipos de dispositivo para permitir que o Google Assistente saiba qual gramática deve ser usada com um dispositivo. As características definem os recursos desse tipo de dispositivo. Cada dispositivo herda os estados de cada característica adicionada a uma integração.

dc8dce0dea87cd5c.png

Você pode conectar as características compatíveis com o tipo escolhido para personalizar a funcionalidade dos dispositivos dos usuários. Se você quiser implementar características personalizados nas ações que não estão disponíveis no esquema do dispositivo, os Modos e Botões de alternância permitem o controle de configurações específicas com um nome personalizado definido por você.

Além da função de controle básica fornecida por tipos e características, a API Smart Home tem recursos adicionais para melhorar a experiência do usuário. As respostas de erro oferecem feedback detalhado do usuário quando as intents falham. A verificação secundária de usuários estende essas respostas e adiciona mais segurança à característica do dispositivo que você escolher. Ao enviar respostas de erro específicas a blocos de desafios emitidos pelo Google Assistente, sua integração de nuvem para nuvem pode exigir uma autorização adicional para concluir um comando.

Pré-requisitos

O que você vai criar

Neste codelab, você vai implantar uma integração de casa inteligente pré-criada com o Firebase e aprender a adicionar características não padrão à lavadora de casa inteligente para a quantidade de carga e o modo turbo. Você também vai implementar relatórios de erros e exceções, além de aprender a aplicar uma confirmação verbal para ativar a lavadora usando a verificação secundária do usuário.

O que você vai aprender

  • Como adicionar as características de modos e botões de alternância à sua integração
  • Como informar erros e exceções
  • Como aplicar a verificação secundária do usuário

O que é necessário

2. Primeiros passos

Ativar Controles de atividade

Para usar o Google Assistente, você precisa compartilhar determinados dados de atividade com o Google. O Google Assistente precisa desses dados para funcionar corretamente. No entanto, esse requisito não é específico do SDK. Para compartilhar os dados, crie uma Conta do Google, caso ainda não tenha. Você pode usar qualquer Conta do Google. Ela não precisa ser sua conta de desenvolvedor.

Abra a página Controles de atividade da Conta do Google que você quer usar com o Google Assistente.

Verifique se os botões a seguir estão ativados:

  • Atividade na Web e de apps: também marque a caixa de seleção Incluir o histórico do Chrome e a atividade em sites, apps e dispositivos que usam serviços do Google.
  • Informações do dispositivo
  • Atividade de voz e áudio

Criar um projeto de integração de nuvem para nuvem

  1. Acesse o Developer Console.
  2. Clique em Criar projeto, insira um nome e clique em Criar projeto.

Nomear projeto

Selecione a integração de nuvem para nuvem

Na página inicial do projeto no Developer Console, selecione Adicionar integração de nuvem para nuvem em Nuvem para nuvem.

Adicionar integração de nuvem para nuvem

instalar a CLI do Firebase

A interface de linha de comando (CLI, na sigla em inglês) do Firebase permite veicular 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 da seguinte forma:

firebase login

Adicionar o Firebase ao projeto do Google Home Developer Console

Método 1: pelo console do Firebase

  1. Acesse Firebase.
  2. Clique em Criar um projeto do Firebase.
    Criar projeto do Firebase
  3. Na tela Criar um projeto, clique em Adicionar o Firebase ao projeto do Google Cloud.
    Adicionar o Firebase ao projeto do Google Cloud
  4. Na tela Começar, selecione o projeto do Google Cloud que você acabou de criar no console do desenvolvedor do Google Home e clique em Continuar.
    Selecionar projeto do Google Cloud

Método 2: pela CLI do Firebase

firebase projects:addfirebase

Selecione o projeto do Google Home Developer Console que você acabou de criar para adicionar o Firebase.

Quando o Firebase é adicionado ao seu projeto do Google Home Developer Console, ele aparece no console do Firebase. O ID do projeto do Firebase será igual ao ID do projeto do Google Home Developer Console.

Projeto do Cloud adicionado

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 <firebase-project-id>.. Em seguida, na tela da biblioteca da API HomeGraph, clique em Ativar.

ee198858a6eac112.png

3. Executar o app inicial

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

Conseguir o 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/google-home/smarthome-traits.git

Faça o download e descompacte o arquivo ZIP.

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.

O fulfillment da nuvem fornecido inclui as seguintes funções em index.js:

  • fakeauth: endpoint de autorização para vinculação de conta
  • faketoken: endpoint de token para vinculação de conta
  • smarthome: endpoint de fulfillment da intent de casa inteligente
  • reportstate: invoca a API Home Graph nas mudanças de estado do dispositivo
  • requestsync: permite atualizações do dispositivo do usuário sem exigir outra vinculação de conta

Conectar-se ao Firebase

Acesse o diretório washer-start e configure a CLI do Firebase com seu projeto de integração:

cd washer-start
firebase use <project-id>

Configurar o projeto do Firebase

Inicialize um projeto do Firebase.

firebase init

Selecione os recursos da CLI, o Realtime Database e o recurso 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

Isso inicializará as APIs e os recursos necessários para seu projeto.

Quando solicitado, inicialize o Realtime Database. É possível usar o local padrão para a instância do banco de dados.

? 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

Como você está usando o código do projeto inicial, escolha o arquivo padrão para as regras de segurança e tome cuidado para não substituir o arquivo de regras do banco de dados.

? 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

Se você estiver reinicializando o projeto, selecione Substituir quando perguntado se quer inicializar ou substituir uma base de código.

? Would you like to initialize a new codebase, or overwrite an existing one?
Overwrite

Ao configurar as Functions, use os arquivos padrão e tome cuidado para não substituir os arquivos index.js e package.json da amostra do projeto.

? 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

Se você estiver reinicializando o projeto, selecione Não quando perguntarem se você quer inicializar ou substituir functions/.gitignore.

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

Se o ESLint foi ativado por engano, há dois métodos disponíveis para desativá-lo:

  1. Na GUI, acesse a pasta ../functions no projeto, selecione o arquivo oculto .eslintrc.js e exclua-o. Não confunda com o .eslintrc.json, que tem um nome parecido.
  2. Usando a linha de comando:
    cd functions
    rm .eslintrc.js
    

Implantar no Firebase

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 você deverá ver:

...

✔ Deploy complete!

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

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

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

5845443e94705557.png

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 Developer Console.

Configurar seu projeto do Developer Console

Na guia Desenvolver, adicione um Nome de exibição para sua interação. Esse nome aparecerá no app Google Home.

Adicionar um nome de exibição

Em Branding do app, faça upload de um arquivo png para o ícone do app, com tamanho de 144 x 144 px e nome .png.

Adicionar um ícone do app

Para ativar a Vinculação de contas, use estas configurações:

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

Atualizar URLs de vinculação de conta

Em URL do fulfillment na nuvem, insira o URL da função do Cloud que oferece fulfillment para as intents de casa inteligente.

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

Adicionar URL da função do Cloud

Clique em Salvar para armazenar a configuração do projeto e, depois, em Próxima: teste para ativar o teste no seu projeto.

Testar sua integração de nuvem para nuvem

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

Para testar a integração de nuvem para nuvem, vincule 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. Clique no ícone de pesquisa no canto superior direito.
  4. Pesquise o app de teste usando o prefixo [test] para encontrar o app específico.
  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.

ae252220753726f6.png

Verifique se é possível controlar a lavadora usando comandos de voz no app Google Home. Você também deve ver a mudança de estado do dispositivo na IU da Web de front-end do seu fulfillment na nuvem.

Agora que você tem uma lavadora básica implantada, pode personalizar os modos disponíveis no dispositivo.

4. Adicionar modos

A seção action.devices.traits.Modes permite que um dispositivo tenha um número arbitrário de configurações para um modo. Só é possível definir uma por vez. Você adicionará um modo à lavadora para definir o tamanho da carga: pequeno, médio ou grande.

Atualizar resposta de sincronização

É necessário adicionar informações sobre a nova característica na sua resposta do SYNC em functions/index.js. Esses dados aparecem na matriz traits e no objeto attributes, conforme o snippet de código a seguir.

index.js

app.onSync(body => {
  return {
    requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    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',
          // Add Modes trait
          'action.devices.traits.Modes',
        ],
        name: { ... },
        deviceInfo: { ... },
        attributes: {
          pausable: true,
          //Add availableModes
          availableModes: [{
            name: 'load',
            name_values: [{
              name_synonym: ['load'],
              lang: 'en',
            }],
            settings: [{
              setting_name: 'small',
              setting_values: [{
                setting_synonym: ['small'],
                lang: 'en',
              }]
            }, {
              setting_name: 'medium',
              setting_values: [{
                setting_synonym: ['medium'],
                lang: 'en',
              }]
            }, {
              setting_name: 'large',
              setting_values: [{
                setting_synonym: ['large'],
                lang: 'en',
              }]
            }],
            ordered: true,
          }],
        },
      }],
    },
  };
});

Adicionar novos comandos da intent EXECUTE

Na intent EXECUTE, adicione o comando action.devices.commands.SetModes conforme o snippet de código a seguir.

index.js

const updateDevice = async (execution,deviceId) => {
  const {params,command} = execution;
  let state, 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;
    // Add SetModes command
    case 'action.devices.commands.SetModes':
      state = {load: params.updateModeSettings.load};
      ref = firebaseRef.child(deviceId).child('Modes');
      break;
  }
};

Atualizar resposta de QUERY

Em seguida, atualize sua resposta de QUERY para informar o estado atual da lavadora.

Adicione as atualizações das funções queryFirebase e queryDevice para receber o estado armazenado no Realtime Database.

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,
    // Add Modes snapshot
    load: snapshotVal.Modes.load,
  };
};

const queryDevice = async (deviceId) => {
  const data = await queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{ ... }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
    // Add currentModeSettings
    currentModeSettings: {
      load: data.load,
    },
  };
};

Atualizar estado do relatório

Por fim, atualize sua função reportstate para informar a configuração de carga atual da lavadora para o Home Graph.

index.js

const requestBody = {
  requestId: 'ff36a3cc', /* Any unique ID */
  agentUserId: USER_ID,
  payload: {
    devices: {
      states: {
        /* Report the current state of your washer */
        [context.params.deviceId]: {
          on: snapshot.OnOff.on,
          isPaused: snapshot.StartStop.isPaused,
          isRunning: snapshot.StartStop.isRunning,
          // Add currentModeSettings
          currentModeSettings: {
            load: snapshot.Modes.load,
          },
        },
      },
    },
  },
};

Implantar no Firebase

Execute o seguinte comando para implantar a integração atualizada:

firebase deploy --only functions

Após a conclusão da implantação, acesse a IU da Web e clique no botão Atualizar ae8d3b25777a5e30.png na barra de ferramentas. Isso aciona uma sincronização de solicitação para que o Google Assistente receba os dados atualizados de resposta do SYNC

bf4f6a866160a982.png

Agora você pode dar um comando para definir o modo da lavadora, como:

"Ok Google, mude a carga de lavagem para grande."

Além disso, é possível fazer perguntas sobre a lavadora, como:

"Ok Google, qual é a carga da lavadora?"

5. Adicionar botões de alternância

A característica action.devices.traits.Toggles representa aspectos nomeados de um dispositivo que tem um estado verdadeiro ou falso. Por exemplo, se a lavadora está no modo turbo.

Atualizar resposta de sincronização

Na resposta de SYNC, você precisa adicionar informações sobre a nova característica do dispositivo. Ela vai aparecer na matriz traits e no objeto attributes, conforme o snippet de código a seguir.

index.js

app.onSync(body => {
  return {
    requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    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',
          'action.devices.traits.Modes',
          // Add Toggles trait
          'action.devices.traits.Toggles',
        ],
        name: { ... },
        deviceInfo: { ... },
        attributes: {
          pausable: true,
          availableModes: [{
            name: 'load',
            name_values: [{
              name_synonym: ['load'],
              lang: 'en'
            }],
            settings: [{ ... }],
            ordered: true,
          }],
          //Add availableToggles
          availableToggles: [{
            name: 'Turbo',
            name_values: [{
              name_synonym: ['turbo'],
              lang: 'en',
            }],
          }],
        },
      }],
    },
  };
});

Adicionar novos comandos da intent EXECUTE

Na intent EXECUTE, adicione o comando action.devices.commands.SetToggles conforme o snippet de código a seguir.

index.js

const updateDevice = async (execution,deviceId) => {
  const {params,command} = execution;
  let state, 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;
    case 'action.devices.commands.SetModes':
      state = {load: params.updateModeSettings.load};
      ref = firebaseRef.child(deviceId).child('Modes');
      break;
    // Add SetToggles command
    case 'action.devices.commands.SetToggles':
      state = {Turbo: params.updateToggleSettings.Turbo};
      ref = firebaseRef.child(deviceId).child('Toggles');
      break;
  }

Atualizar resposta de QUERY

Por fim, você precisa atualizar sua resposta de QUERY para informar que a lavadora está no modo turbo. Adicione as alterações atualizadas às funções queryFirebase e queryDevice para receber o estado de alternância conforme armazenado no Realtime Database.

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,
    load: snapshotVal.Modes.load,
    // Add Toggles snapshot
    Turbo: snapshotVal.Toggles.Turbo,
  };
}

const queryDevice = async (deviceId) => {
  const data = queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{ ... }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
    currentModeSettings: {
      load: data.load,
    },
    // Add currentToggleSettings
    currentToggleSettings: {
      Turbo: data.Turbo,
    },
  };
};

Atualizar estado do relatório

Por fim, atualize a função reportstate para informar ao Home Graph se a lavadora está no modo turbo.

index.js

const requestBody = {
  requestId: 'ff36a3cc', /* Any unique ID */
  agentUserId: USER_ID,
  payload: {
    devices: {
      states: {
        /* Report the current state of your washer */
        [context.params.deviceId]: {
          on: snapshot.OnOff.on,
          isPaused: snapshot.StartStop.isPaused,
          isRunning: snapshot.StartStop.isRunning,
          currentModeSettings: {
            load: snapshot.Modes.load,
          },
          // Add currentToggleSettings
          currentToggleSettings: {
            Turbo: snapshot.Toggles.Turbo,
          },
        },
      },
    },
  },
};

Implantar no Firebase

Execute o seguinte comando para implantar as funções atualizadas:

firebase deploy --only functions

Clique no botão Atualizar ae8d3b25777a5e30.png na interface da Web para acionar uma solicitação de sincronização após a conclusão da implantação.

Agora, você pode usar um comando para definir a lavadora no modo turbo. Basta dizer:

"Ok Google, coloque a lavadora no modo turbo."

Você também pode verificar se a lavadora já está no modo turbo. Basta perguntar:

"Ok Google, a lavadora está no modo turbo?"

6. Como relatar erros e exceções

O gerenciamento de erros na sua integração de nuvem para nuvem permite que você informe aos usuários quando os problemas causarem falhas nas respostas de EXECUTE e QUERY. As notificações criam uma experiência mais positiva quando os usuários interagem com o dispositivo inteligente e a integração.

Sempre que uma solicitação de EXECUTE ou QUERY falhar, sua integração vai retornar um código de erro. Se, por exemplo, você quisesse gerar um erro quando um usuário tentasse iniciar a lavagem com a tampa aberta, sua resposta EXECUTE seria como a seguinte:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "456"
        ],
        "status": "ERROR",
        "errorCode": "deviceLidOpen"
      }
    ]
  }
}

Agora, quando um usuário pede para iniciar a lavadora, o Google Assistente responde o seguinte:

"A tampa da lavadora está aberta. Feche e tente novamente."

As exceções são semelhantes aos erros, mas indicam quando um alerta está associado a um comando, que pode ou não bloquear a execução. Uma exceção pode fornecer informações relacionadas usando a característica StatusReport, como o nível da bateria ou uma alteração de estado recente. Códigos de exceção sem bloqueios retornam com um status SUCCESS, e os sem bloqueios retornam com um status EXCEPTIONS.

Um exemplo de resposta com exceção está no seguinte snippet de código:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "SUCCESS",
      "states": {
        "online": true,
        "isPaused": false,
        "isRunning": false,
        "exceptionCode": "runCycleFinished"
      }
    }]
  }
}

O Google Assistente dá a seguinte resposta:

"A lavadora terminou o ciclo."

Para adicionar Error Reporting à sua lavadora, abra functions/index.js e adicione a definição da classe de erro, conforme o seguinte snippet de código:

index.js

app.onQuery(async (body) => {...});

// Add SmartHome error handling
class SmartHomeError extends Error {
  constructor(errorCode, message) {
    super(message);
    this.name = this.constructor.name;
    this.errorCode = errorCode;
  }
}

Atualize a resposta de execução para retornar o status e o código do erro:

index.js

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) => {
          ...
        })
        //Add error response handling
        .catch((error) => {
          functions.logger.error('EXECUTE', device.id, error);
          result.ids.push(device.id);
          if (error instanceof SmartHomeError) {
            result.status = 'ERROR';
            result.errorCode = error.errorCode;
          }
        })
      );
    }
  }
}

Agora, o Google Assistente pode avisar seus usuários sobre qualquer código de erro informado. Você verá um exemplo específico na próxima seção.

7. Adicionar verificação secundária do usuário

Você precisa implementar a verificação secundária do usuário na sua integração se o dispositivo tiver modos que precisam ser protegidos ou limitados a um grupo específico de usuários autorizados, como uma atualização de software ou um desbloqueio.

Você pode implementar a verificação secundária do usuário em todos os tipos e as características de dispositivos. Para isso, é preciso personalizar se o desafio de segurança ocorre todas as vezes ou conforme critérios específicos.

três tipos de desafio compatíveis:

  • No challenge: uma solicitação e uma resposta que não usam um desafio de autenticação (é o comportamento padrão)
  • ackNeeded: uma verificação secundária do usuário que requer confirmação explícita (sim ou não)
  • pinNeeded: uma verificação secundária do usuário que exige um PIN (Número de identificação pessoal)

Neste codelab, você vai adicionar um desafio ackNeeded ao comando para ativar a lavadora e a funcionalidade de retornar um erro se a verificação secundária falhar.

Abra functions/index.js e adicione uma definição de classe de erro que retorne o código do erro e o tipo de desafio, conforme o seguinte snippet de código:

index.js

class SmartHomeError extends Error { ... }

// Add secondary user verification error handling
class ChallengeNeededError extends SmartHomeError {
  /**
   * Create a new ChallengeNeededError
   * @param {string} suvType secondary user verification challenge type
   */
  constructor(suvType) {
    super('challengeNeeded', suvType);
    this.suvType = suvType;
  }
}

Também é preciso atualizar a resposta de execução para retornar o erro challengeNeeded da seguinte maneira:

index.js

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) => {
          ...
        })
        .catch((error) => {
          functions.logger.error('EXECUTE', device.id, error);
          result.ids.push(device.id);
          if (error instanceof SmartHomeError) {
            result.status = 'ERROR';
            result.errorCode = error.errorCode;
            //Add error response handling
            if (error instanceof ChallengeNeededError) {
              result.challengeNeeded = {
                type: error.suvType
              };
            }
          }
        })
      );
    }
  }
}

Por fim, modifique updateDevice para exigir a confirmação explícita para ativar ou desativar a lavadora.

index.js

const updateDevice = async (execution,deviceId) => {
  const {challenge,params,command} = execution; //Add secondary user challenge
  let state, ref;
  switch (command) {
    case 'action.devices.commands.OnOff':
      //Add secondary user verification challenge
      if (!challenge || !challenge.ack) {
        throw new ChallengeNeededError('ackNeeded');
      }
      state = {on: params.on};
      ref = firebaseRef.child(deviceId).child('OnOff');
      break;
    ...
  }

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

Implantar no Firebase

Execute o seguinte comando para implantar a função atualizada:

firebase deploy --only functions

Depois de implantar o código atualizado, você precisará confirmar verbalmente a ação ao pedir que o Google Assistente ative ou desative a lavadora, desta forma:

Você: "Ok Google, ligue a lavadora."

O Google Assistente: "Você quer mesmo ativar a lavadora?"

Você: "Sim."

Você também pode ver uma resposta detalhada para cada etapa do fluxo de verificação secundária do usuário. Basta abrir os registros do Firebase.

289dbe48f4bb8106.png

8. Parabéns

674c4f4392e98c1.png

Parabéns! Você estendeu os recursos das integrações de nuvem para nuvem com as características Modes e Toggles, além de proteger a execução com a verificação secundária do usuário.

Saiba mais

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

  • Adicione recursos de execução local aos dispositivos.
  • Use outro tipo de desafio de verificação secundária do usuário para modificar o estado do dispositivo.
  • Atualize a característica de QUERY RunCycle para fazer uma atualização dinâmica.
  • Confira este exemplo do GitHub.