Sobre este codelab
1. Antes de começar
As ações de casa inteligente 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 ação.
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 autenticação de dois fatores (2FA) estende essas respostas e adiciona mais segurança à característica do dispositivo que você escolher. Quando você envia respostas de erro específicas a blocos de desafios emitidos pelo Google Assistente, sua ação de casa inteligente pode exigir uma autorização adicional para concluir um comando.
Pré-requisitos
- Guia do desenvolvedor: Criar uma ação de casa inteligente
- Codelab: lavadora de casa inteligente
- Guia do desenvolvedor sobre Características e tipos de dispositivos
O que você criará
Neste codelab, você implantará uma integração de casa inteligente pré-criada com o Firebase e, em seguida, 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 autenticação de dois fatores.
O que você aprenderá
- Como adicionar as características de modos e botões de alternância à sua ação
- Como informar erros e exceções
- Como aplicar a autenticação de dois fatores
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 do Google
- Uma conta de faturamento do Google Cloud
2. Primeiros passos
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 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
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 tela da biblioteca da API HomeGraph, clique em Ativar.
3. Executar o app inicial
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-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 contafaketoken
**:** endpoint de token para vinculação de contasmarthome
**:** endpoint de fulfillment da intent de casa inteligentereportstate
**:** invoca a API HomeGraph nas alterações de estado do dispositivorequestsync
**:** 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 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
O 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 ().
Vincular ao Google Assistente
Para testar a ação de 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
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.
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 a``ction.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 açã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 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
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 aparecerá na matriz de 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 na IU 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, ligue o modo turbo na lavadora."
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 ação de casa inteligente 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 ação.
Sempre que uma solicitação de EXECUTE
ou QUERY
falhar, sua ação 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( ... )
//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 autenticação de dois fatores
Você precisa implementar a autenticação de dois fatores (2FA) na sua açã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 autenticação de dois fatores 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.
Existem 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 autenticação de dois fatores que requer confirmação explícita (sim ou não)pinNeeded
: autenticação de dois fatores 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 autenticação de dois fatores 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 2FA error handling
class ChallengeNeededError extends SmartHomeError {
constructor(tfaType) {
super('challengeNeeded', tfaType);
this.tfaType = tfaType;
}
}
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( ... )
.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 2FA error handling
if(error instanceof ChallengeNeededError) {
result.challengeNeeded = {
type: error.tfaType
};
}
}
})
);
}
}
}
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 2FA challenge
let state, ref;
switch (command) {
case 'action.devices.commands.OnOff':
//Add 2FA 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 autenticação de dois fatores. Basta abrir os registros do Firebase.
8. Parabéns
Parabéns! Você estendeu os recursos das ações de casa inteligente com as características Modes
e Toggles
, além de proteger a execução com a autenticação de dois fatores.
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 autenticação de dois fatores para modificar o estado do dispositivo.
- Atualize a característica de QUERY
RunCycle
para fazer uma atualização dinâmica. - Explore este exemplo do GitHub.