1. Introdução
O programa Acesso a Dispositivos fornece a API Smart Device Management, uma API REST para que os desenvolvedores controlem os dispositivos Google Nest nos apps deles. Os usuários precisam permitir que terceiros acessem os dispositivos Nest.
Há três etapas principais para a integração do Acesso a Dispositivos:
- Criação de projetos: crie um projeto no Google Cloud Platform e inscreva-se como desenvolvedor no Console do Acesso a Dispositivos.
- Vinculação de contas: faça os usuários passarem pelo fluxo de vinculação de contas e receberem um código de acesso. Troque o código por um token de acesso.
- Controle do dispositivo: faça solicitações na API Smart Device Management para controlar os dispositivos ao enviar comandos com o token de acesso.
Neste codelab, vamos criar um app da Web que lida com autenticação e chamar a API Smart Device Management para entender melhor como o Acesso a Dispositivos funciona. Também mostraremos como implantar um servidor proxy simples usando o Node.js e Express para encaminhar as solicitações do Acesso a Dispositivos.
Antes de começar, é recomendável recapitular as tecnologias mais comuns da Web que usaremos neste codelab, como a autenticação com OAuth 2.0 ou a criação de um app da Web com Node.js, embora isso não seja um pré-requisito.
Pré-requisitos
- Node.js 8 ou mais recente
- Conta do Google com um Nest Thermostat vinculado
O que você vai aprender
- Como configurar um projeto do Firebase que hospeda páginas da Web estáticas e o Cloud Functions
- Como emitir solicitações de acesso a dispositivos usando um app da Web baseado em navegador
- Como criar um servidor proxy com Node.js e Express para encaminhar suas solicitações
2. Criação do projeto
Os desenvolvedores precisam criar um projeto do Google Cloud Platform (GCP) para configurar a integração do Acesso a Dispositivos. Usaremos um ID do cliente e uma chave secreta gerados no projeto do GCP como parte do fluxo do OAuth entre o app do desenvolvedor e o Google Cloud. Os desenvolvedores também precisam acessar o Console do Acesso a Dispositivos para criar um projeto que acessa a API Smart Device Management.
Google Cloud Platform
Acessar o Google Cloud Platform Clique em "Criar um novo projeto" e crie um nome para ele. O ID do projeto [GCP-Project-Id] para o Google Cloud também será exibido. Não perca esse ID, pois ele será usado durante a configuração do Firebase. Chamaremos esse ID de [GCP-Project-Id] neste codelab.
A primeira etapa é ativar a biblioteca de APIs necessária no nosso projeto. Acesse APIs e Serviços > Biblioteca e procure a API Smart Device Management. Você precisa ativar essa API para autorizar seu projeto a fazer solicitações para chamadas de API do Acesso a Dispositivos.
Antes de prosseguirmos para criar as credenciais do OAuth, precisamos configurar a tela de permissão OAuth do nosso projeto. Acesse APIs e Serviços > Tela de permissão OAuth Em Tipo de usuário, escolha externo. Para concluir a primeira tela, forneça um nome e um e-mail de suporte para o app, além de dados de contato do desenvolvedor. Na solicitação de Usuários de teste, forneça o endereço de e-mail com os dispositivos vinculados nessa etapa.
Depois de configurar a tela de permissão OAuth, acesse APIs e Serviços > Credenciais. Clique em +Criar credenciais e selecione ID do cliente OAuth. No tipo de app, selecione app da Web.
Dê um nome ao cliente e clique em CRIAR. Adicionaremos uma origem de JavaScript autorizada e um URI de redirecionamento autorizado mais tarde. Ao concluir esse processo, o [Client-Id] e a [Client-Secret] associados a esse cliente do OAuth 2.0 serão exibidos.
Console do Acesso a Dispositivos
Acesse o Console do Acesso a Dispositivos. Se você nunca usou o Console do Acesso a Dispositivos, o contrato dos Termos de Serviço será exibido e haverá uma taxa de registro de US$ 5.
Crie um projeto e dê um nome a ele. Na próxima janela, forneça o [Client-Id] que você recebeu do GCP na etapa anterior.
Ao ativar os eventos e concluir as etapas de criação do projeto, a página inicial do seu projeto será aberta. O [Project-Id] será exibido abaixo do nome dado ao projeto.
Anote o [Project-Id]: ele será usado para enviar solicitações à API Smart Device Management.
3. Configuração do Firebase
O Firebase oferece aos desenvolvedores uma maneira rápida e fácil de implantar apps da Web. Nós vamos desenvolver um app da Web no lado do cliente para a integração do Acesso a Dispositivos usando o Firebase.
Criar um projeto do Firebase
Acesse o Console do Firebase. Clique em Adicionar projeto e selecione o que você criou na etapa Criação do projeto. O projeto será criado no Firebase e vinculado ao seu projeto do GCP [GCP-Project-Id].
Depois que o projeto do Firebase for criado, aparecerá a seguinte tela:
Instalar as ferramentas do Firebase
O Firebase oferece um conjunto de ferramentas de CLI para criar e implantar seu app. Para instalar essas ferramentas, abra uma nova janela do terminal e execute o comando a seguir. As ferramentas do Firebase serão instaladas globalmente.
$ npm i -g firebase-tools
Para verificar se as ferramentas do Firebase estão instaladas corretamente, confira as informações da versão.
$ firebase --version
Você pode fazer login nas ferramentas da CLI do Firebase com sua Conta do Google usando o comando de login.
$ firebase login
Inicializar um projeto de hospedagem
Depois de fazer login, a próxima etapa é inicializar um projeto de hospedagem para o app da Web. No terminal, navegue até a pasta onde você quer criar o projeto e execute o seguinte comando:
$ firebase init hosting
O Firebase fará algumas perguntas para começar a criar o projeto de hospedagem:
- Selecione uma opção: Usar um dos projetos
- Selecione um projeto padrão do Firebase para esse diretório: selecione ***[GCP-Project-Id]***.
- O que você quer usar como diretório público? Público
- Configurar como app de página única? Sim
- Configurar versões e implantações automáticas com o GitHub? Não
Depois que o projeto for inicializado, você poderá implantá-lo no Firebase com o seguinte comando:
$ firebase deploy
O Firebase vai verificar seu projeto e implantar os arquivos necessários na hospedagem em nuvem.
Ao abrir o URL do Hosting em um navegador, você verá a página que acabou de implantar:
Agora que você já sabe o básico sobre como implantar uma página da Web com o Firebase, vamos implantar o exemplo do codelab.
4. Exemplo de codelab
Use o comando abaixo para clonar o repositório do codelab hospedado no GitHub:
$ git clone https://github.com/google/device-access-codelab-web-app.git
Nesse repositório, fornecemos exemplos em duas pastas diferentes. A pasta codelab-start
tem os arquivos necessários para você começar do ponto atual deste codelab. A pasta codelab-done
contém uma versão completa deste codelab, com o cliente totalmente funcional e o servidor Node.js.
Usaremos os arquivos da pasta codelab-start
para este codelab. Se em algum momento você não souber o que fazer, consulte também a versão codelab-done.
Arquivos de exemplo do codelab
A estrutura de arquivos da pasta codelab-start é a seguinte:
public ├───index.html ├───scripts.js ├───style.css firebase.json
A pasta pública contém páginas estáticas do nosso app. O firebase.json
é responsável por rotear solicitações da Web para nosso app. Na versão codelab-done
, você também verá um diretório functions
que contém a lógica para que nosso servidor proxy (Express) seja implantado no Cloud Functions.
Implantar exemplo do codelab
Copie os arquivos do codelab-start
para o diretório do projeto.
$ firebase deploy
Depois que o Firebase for implantado, você verá o app do codelab:
A inicialização do fluxo de autenticação exige credenciais de parceiro, o que será abordado na próxima seção.
5. Processar o OAuth
OAuth é o padrão da Web para delegação de acesso, comumente usado para que os usuários concedam a apps de terceiros acesso às informações da conta sem compartilhar senhas. Usamos o OAuth 2.0 para permitir que os desenvolvedores acessem os dispositivos dos usuários pelo Acesso a Dispositivos.
Especificar o URI de redirecionamento
A primeira etapa do fluxo do OAuth envolve a transmissão de um conjunto de parâmetros para o endpoint do Google OAuth 2.0. Depois de receber o consentimento do usuário, os servidores do Google OAuth emitirão uma solicitação com um código de autorização para o URI de redirecionamento.
Atualize a constante SERVER_URI
(linha 19) com seu próprio URL do Hosting no scripts.js
:
const SERVER_URI = "https://[GCP-Project-Id].web.app";
A reimplantação do app com essa mudança atualizará o URI de redirecionamento usado para seu projeto.
$ firebase deploy
Ativar o URI de redirecionamento
Depois de atualizar o URI de redirecionamento no arquivo de scripts, também é preciso adicioná-lo à lista de URIs de redirecionamento permitidos para o ID do cliente criado para o projeto. Acesse a página Credenciais no Google Cloud Platform para ver as credenciais criadas para seu projeto:
Na lista de IDs do cliente OAuth 2.0, selecione o ID criado na etapa Criação de projeto. Adicione o URI de redirecionamento do seu app à lista de URIs de redirecionamento autorizados do seu projeto.
Testar o login
Acesse o URL do Hosting que você configurou com o Firebase, insira suas credenciais de parceiro e clique no botão LOGIN. O ID e a chave secreta do cliente são as credenciais que você recebeu do Google Cloud Platform. O ID do projeto é do Console do Acesso a Dispositivos.
O botão LOGIN vai direcionar os usuários pelo fluxo do OAuth da sua empresa, começando com a tela de login na Conta do Google. Depois de fazer login, os usuários devem fornecer permissões para que seu projeto acesse os dispositivos Nest deles.
Como esse é um app fictício, o Google emitirá um aviso antes do redirecionamento.
Clique em "Avançado" e selecione "Acessar web.app (não seguro)" para concluir o redirecionamento para seu app.
Isso fornece um código OAuth como parte da solicitação GET de entrada, que o app trocará por um token de acesso e um token de atualização.
6. Controle do dispositivo
O app de exemplo Acesso a Dispositivos usa chamadas da API REST Smart Device Management para controlar dispositivos Google Nest. Essas chamadas envolvem a transmissão do token de acesso no cabeçalho de uma solicitação GET ou POST, assim como um payload necessário para determinados comandos.
Nós escrevemos uma função de solicitação de acesso genérica para lidar com essas chamadas. No entanto, você deve fornecer o endpoint correto e, quando necessário, o objeto de payload para essa função.
function deviceAccessRequest(method, call, localpath, payload = null) {...}
- method: tipo de solicitação HTTP (
GET
ouPOST)
) - call: uma string que representa nossa chamada de API, usada para encaminhar respostas (
listDevices
,thermostatMode
,temperatureSetpoint
) - localpath: endpoint para o qual a solicitação é feita, contendo o ID do projeto e o ID do dispositivo (incluídos após
https://smartdevicemanagement.googleapis.com/v1
) - payload (*): outros dados necessários para a chamada de API, como um valor numérico que representa uma temperatura programada
Criaremos controles de IU de exemplo (Listar dispositivos, Definir modo, Definir temperatura) para controlar um Nest Thermostat:
Esses controles de IU chamarão as funções correspondentes (listDevices()
, postThermostatMode()
, postTemperatureSetpoint()
) em scripts.js
. Eles ficarão em branco para você implementar. O objetivo é escolher o método/caminho correto e transmitir o payload para a função deviceAccessRequest(...)
.
Listar dispositivos
A chamada do Acesso a Dispositivos mais simples é a listDevices
. Ela usa uma solicitação GET
e não requer payload. O endpoint precisa ser estruturado usando o projectId
. Conclua a função listDevices()
da seguinte maneira:
function listDevices() { var endpoint = "/enterprises/" + projectId + "/devices"; deviceAccessRequest('GET', 'listDevices', endpoint); }
Salve as mudanças e implante o projeto do Firebase novamente com o comando a seguir:
$ firebase deploy
Após a implantação da nova versão do app, atualize a página e clique em LISTAR DISPOSITIVOS. A lista exibida em "Controle do dispositivo" será preenchida, e você verá o ID do termostato:
A seleção de dispositivos na lista atualizará o campo deviceId
no arquivo scripts.js
. Nos próximos dois controles, precisamos especificar o deviceId
para o dispositivo que queremos controlar.
Controle do termostato
Há duas características do controle básico de um Nest Thermostat na API Smart Device Management: ThermostatMode e TemperatureSetpoint. A ThermostatMode define o modo do Nest Thermostat como um dos quatro modos possíveis: {Off, Heat, Cool, HeatCool}. Em seguida, precisamos fornecer o modo selecionado como parte do payload.
Substitua a função postThermostatMode()
no scripts.js
pelo seguinte:
function postThermostatMode() { var endpoint = "/enterprises/" + projectId + "/devices/" + deviceId + ":executeCommand"; var tempMode = id("tempMode").value; var payload = { "command": "sdm.devices.commands.ThermostatMode.SetMode", "params": { "mode": tempMode } }; deviceAccessRequest('POST', 'thermostatMode', endpoint, payload); }
A próxima função, postTemperatureSetpoint()
, cuida da definição da temperatura (em Celsius) do Nest Thermostat. É possível definir dois parâmetros no payload, heatCelsius
e coolCelsius
, dependendo do modo de termostato selecionado.
function postTemperatureSetpoint() { var endpoint = "/enterprises/" + projectId + "/devices/" + deviceId + ":executeCommand"; var heatCelsius = parseFloat(id("heatCelsius").value); var coolCelsius = parseFloat(id("coolCelsius").value); var payload = { "command": "", "params": {} }; if ("HEAT" === id("tempMode").value) { payload.command = "sdm.devices.commands.ThermostatTemperatureSetpoint.SetHeat"; payload.params["heatCelsius"] = heatCelsius; } else if ("COOL" === id("tempMode").value) { payload.command = "sdm.devices.commands.ThermostatTemperatureSetpoint.SetCool"; payload.params["coolCelsius"] = coolCelsius; } else if ("HEATCOOL" === id("tempMode").value) { payload.command = "sdm.devices.commands.ThermostatTemperatureSetpoint.SetRange"; payload.params["heatCelsius"] = heatCelsius; payload.params["coolCelsius"] = coolCelsius; } else { console.log("Off and Eco mode don't allow this function"); return; } deviceAccessRequest('POST', 'temperatureSetpoint', endpoint, payload); }
7. Servidor Node.js (opcional)
Parabéns, Você criou um app da Web do lado do cliente que pode fazer solicitações da API Smart Device Management em um navegador. Se quiser criar do lado do servidor, ajudaremos com um servidor proxy que pode redirecionar suas solicitações do navegador.
Para esse servidor proxy, usaremos o Cloud Functions do Firebase, o Node.js e o Express.
Inicializar o Cloud Functions
Abra uma nova janela do terminal, navegue até o diretório do projeto e execute o seguinte:
$ firebase init functions
O Firebase fará algumas perguntas para inicializar o Cloud Functions:
- Qual linguagem você quer usar para programar o Cloud Functions? JavaScript
- Você quer usar o ESlint para identificar prováveis bugs e aplicar o estilo? Não
- Você quer instalar dependências com o NPM agora? Sim
Isso inicializará uma pasta functions
no seu projeto, além de instalar as dependências necessárias. Você verá que a pasta do projeto contém um diretório de funções com um arquivo index.js para definir o Cloud Functions, um package.json para definir as configurações e um node_modules que contém as dependências.
Usaremos duas bibliotecas npm
para criar a funcionalidade do lado do servidor: express e xmlhttprequest. Você precisará adicionar as seguintes entradas à lista de dependências no arquivo package.json:
"xmlhttprequest": "^1.8.0", "express": "^4.17.0"
Em seguida, ao executar a instalação do npm a partir do diretório de funções, as dependências do projeto serão instaladas:
$ npm install
Caso o npm tenha algum problema com o download dos pacotes, salve explicitamente o xmlhttprequest e o Express com o seguinte comando:
$ npm install express xmlhttprequest --save
Fazer upgrade para o plano Blaze
Para usar o comando firebase deploy
, será preciso fazer upgrade para o plano Blaze, que exige a inclusão de uma forma de pagamento à sua conta. Acesse Visão geral do projeto > Uso e faturamento e selecione o plano Blaze.
Criar o servidor Express
Um servidor Express segue um framework simples para responder às solicitações GET
e POST
de entrada. Criamos um servlet que ouve solicitações POST
, as transmite para um URL de destino especificado no payload e responde com a resposta recebida da transferência.
Modifique o arquivo index.js
no diretório de funções para que ele fique assim:
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; const functions = require('firebase-functions'); const express = require('express'); const http = require('http'); const app = express(); app.use(express.json()); //***** Device Access - Proxy Server *****// // Serving Get Requests (Not used) app.get('*', (request, response) => { response.status(200).send("Hello World!"); }); // Serving Post Requests app.post('*', (request, response) => { setTimeout(() => { // Read the destination address from payload: var destination = request.body.address; // Create a new proxy post request: var xhr = new XMLHttpRequest(); xhr.open('POST', destination); // Add original headers to proxy request: for (var key in request.headers) { var value = request.headers[key]; xhr.setRequestHeader(key, value); } // Add command/parameters to proxy request: var newBody = {}; newBody.command = request.body.command; newBody.params = request.body.params; // Respond to original request with the response coming // back from proxy request (to Device Access Endpoint) xhr.onload = function () { response.status(200).send(xhr.responseText); }; // Send the proxy request! xhr.send(JSON.stringify(newBody)); }, 1000); }); // Export our app to firebase functions: exports.app = functions.https.onRequest(app);
Para encaminhar solicitações ao nosso servidor, precisamos ajustar as substituições do firebase.json
da seguinte forma:
{ "hosting": { "public": "public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [{ "source": "/proxy**", "function": "app" },{ "source": "**", "destination": "/index.html" } ] } }
Isso encaminhará os URLs que começam com /proxy
para nosso servidor Express, enquanto o restante continuará acessando index.html
.
Chamadas de API do proxy
Agora que nosso servidor está pronto, vamos definir um URI de proxy no scripts.js
para que o navegador envie solicitações a este endereço:
const PROXY_URI = SERVER_URI + "/proxy";
Em seguida, adicione uma função proxyRequest
no scripts.js
, que tem a mesma assinatura da função deviceAccessRequest(...)
, para chamadas indiretas do Acesso a Dispositivos.
function proxyRequest(method, call, localpath, payload = null) { var xhr = new XMLHttpRequest(); // We are doing our post request to our proxy server: xhr.open(method, PROXY_URI); xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken); xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); xhr.onload = function () { // Response is passed to deviceAccessResponse function: deviceAccessResponse(call, xhr.response); }; // We are passing the device access endpoint in address field of the payload: payload.address = "https://smartdevicemanagement.googleapis.com/v1" + localpath; if ('POST' === method && payload) xhr.send(JSON.stringify(payload)); else xhr.send(); }
A última etapa é substituir as chamadas deviceAccessRequest(...)
pela função proxyRequest(...)
nas funções postThermostatMode()
e postTemperatureSetpoint()
dentro do scripts.js
.
Execute firebase deploy
para atualizar o app.
$ firebase deploy
Agora você tem um servidor proxy Node.js em execução usando o Express no Cloud Functions.
Fornecer permissões da função do Cloud
A última etapa é verificar as permissões de acesso do Cloud Functions e se o app do lado do cliente poderá chamá-las.
No Google Cloud Platform, acesse a guia Cloud Functions no menu e selecione a função do Cloud:
Clique em Permissões e em Adicionar membro. Escreva allUsers no novo campo de membros e selecione o papel Cloud Functions > Invocador do Cloud Functions. Clique em "Salvar" para exibir a seguinte mensagem de aviso:
Selecione "Permitir acesso público" para que o app do lado do cliente possa usar sua Função do Cloud.
Parabéns! Você concluiu todas as etapas. Agora você pode acessar seu app da Web e usar os controles do dispositivo roteados pelo servidor proxy.
Próximas etapas
Quer ampliar seus conhecimentos sobre o Acesso a Dispositivos? Confira a documentação de características para saber mais sobre como controlar outros dispositivos Nest e o processo de certificação para aprender as etapas de lançamento do seu produto.
Desenvolva ainda mais suas habilidades com o app de exemplo da Web do Acesso a Dispositivos. Nele, você poderá aprofundar a experiência do codelab e implantar um app da Web em funcionamento para controlar câmeras, campainhas e termostatos Nest.