1. Introduzione
Il programma Device Access fornisce l'API Smart Device Management, un'API REST che consente agli sviluppatori di controllare i dispositivi Google Nest dalle loro applicazioni. Gli utenti devono dare il consenso all'accesso di terze parti ai propri dispositivi Nest.

Esistono tre passaggi chiave per un'integrazione riuscita di Device Access:
- Creazione del progetto: crea un progetto in Google Cloud Platform e registrati come sviluppatore nella console Device Access.
- Collegamento dell'account: guida gli utenti attraverso il flusso di collegamento dell'account e recupera un codice di accesso. Scambia il codice con un token di accesso.
- Controllo dispositivo: effettua richieste API Smart Device Management per controllare i dispositivi inviando comandi con il token di accesso.
In questo codelab esamineremo in dettaglio il funzionamento di Device Access creando un'applicazione web che gestisce l'autenticazione ed effettua chiamate all'API Smart Device Management. Esploreremo anche il deployment di un semplice server proxy utilizzando Node.js ed Express per instradare le richieste di accesso al dispositivo.
Prima di iniziare, sarebbe utile ripassare le tecnologie web comuni che utilizzeremo in questo codelab, come l'autenticazione con OAuth 2.0 o la creazione di un'app web con Node.js, anche se non sono prerequisiti.
Che cosa ti serve
- Node.js 8 o versioni successive
- Account Google con un termostato Nest collegato
Obiettivi didattici
- Configurazione di un progetto Firebase che ospita pagine web statiche e funzioni cloud
- Emissione di richieste di accesso al dispositivo tramite un'applicazione web basata su browser
- Creazione di un server proxy con Node.js ed Express per instradare le richieste
2. Creazione del progetto
Gli sviluppatori devono creare un progetto Google Cloud per configurare l'integrazione di Device Access. Un ID client e un segreto client generati all'interno del progetto GCP verranno utilizzati nell'ambito del flusso OAuth tra l'applicazione dello sviluppatore e Google Cloud. Gli sviluppatori devono anche visitare la console di Accesso ai dispositivi per creare un progetto per accedere all'API Smart Device Management.
Piattaforma Google Cloud
Vai a Google Cloud Platform. Fai clic su Crea un nuovo progetto e fornisci un nome per il progetto. Verrà visualizzato anche un ID progetto [GCP-Project-Id] per Google Cloud. Registralo perché lo utilizzeremo durante la configurazione di Firebase. In questo codelab, faremo riferimento a questo ID come [GCP-Project-Id].

Il primo passaggio consiste nell'abilitare la libreria API necessaria nel nostro progetto. Vai ad API e servizi > Libreria e cerca l'API Smart Device Management. Devi abilitare questa API per autorizzare il tuo progetto a effettuare richieste alle chiamate API Device Access.

Prima di procedere alla creazione delle credenziali OAuth, dobbiamo configurare la schermata per il consenso OAuth per il nostro progetto. Vai a API e servizi > Schermata consenso OAuth. In Tipo di utente, scegli Esterno. Fornisci un nome e un'email di assistenza per la tua app, nonché i dati di contatto dello sviluppatore per completare la prima schermata. Quando ti viene chiesto di inserire gli Utenti di test, assicurati di fornire l'indirizzo email con i dispositivi collegati in questo passaggio.
Dopo aver configurato la schermata per il consenso OAuth, vai ad API e servizi > Credenziali. Fai clic su +Crea credenziali e seleziona ID client OAuth. Come tipo di applicazione, seleziona Applicazione web.

Fornisci un nome per il client e fai clic su CREA. Aggiungeremo un'origine JavaScript autorizzata e un URI di reindirizzamento autorizzato in un secondo momento. Al termine di questa procedura, verranno visualizzati [Client-Id] e [Client-Secret] associati a questo client OAuth 2.0.

Console Accesso ai dispositivi
Vai alla console Accesso ai dispositivi. Se non hai mai utilizzato la Console Accesso ai dispositivi, ti verrà chiesto di accettare i Termini di servizio e di pagare una quota di registrazione di 5 $.
Crea un nuovo progetto e assegnagli un nome. Nella finestra successiva, fornisci l'[ID client] che hai ricevuto da GCP nel passaggio precedente.

L'attivazione degli eventi e il completamento dei passaggi di creazione del progetto ti porteranno alla home page del progetto. Il tuo [Project-Id] verrà elencato sotto il nome che hai assegnato al progetto.

Prendi nota del tuo [Project-Id], in quanto lo utilizzeremo per inviare richieste all'API Smart Device Management.
3. Configurazione di Firebase
Firebase offre agli sviluppatori un modo semplice e veloce per eseguire il deployment di applicazioni web. Svilupperemo un'applicazione web lato client per la nostra integrazione di Device Access utilizzando Firebase.
Crea un progetto Firebase
Vai alla Console Firebase. Fai clic su Aggiungi progetto, quindi seleziona il progetto che hai creato nel passaggio Creazione progetto. Verrà creato un progetto Firebase, che verrà collegato al tuo progetto GCP [GCP-Project-Id].
Una volta creato il progetto Firebase, dovresti visualizzare la seguente schermata:

Installa gli strumenti Firebase
Firebase fornisce un insieme di strumenti CLI per creare e distribuire la tua app. Per installare questi strumenti, apri una nuova finestra del terminale ed esegui il comando seguente. In questo modo, gli strumenti Firebase verranno installati a livello globale.
$ npm i -g firebase-tools
Per verificare che gli strumenti Firebase siano installati correttamente, controlla le informazioni sulla versione.
$ firebase --version
Puoi accedere agli strumenti dell'interfaccia a riga di comando di Firebase con il tuo Account Google utilizzando il comando di accesso.
$ firebase login
Inizializza il progetto host
Una volta effettuato l'accesso, il passaggio successivo è inizializzare un progetto di hosting per la tua applicazione web. Dal terminale, vai alla cartella in cui vuoi creare il progetto ed esegui questo comando:
$ firebase init hosting
Firebase ti porrà una serie di domande per iniziare a utilizzare un progetto di hosting:
- Seleziona un'opzione: Utilizza un progetto esistente
- Seleziona un progetto Firebase predefinito per questa directory: Scegli ***[GCP-Project-Id]***
- Cosa vuoi utilizzare come directory pubblica? — Pubblico
- Configurare come app a pagina singola? — Sì
- Configurare build e deployment automatici con GitHub? — No
Una volta inizializzato il progetto, puoi eseguirne il deployment su Firebase con il seguente comando:
$ firebase deploy
Firebase eseguirà la scansione del progetto e il deployment dei file necessari nell'hosting cloud.

Quando apri l'URL di hosting in un browser, dovresti vedere la pagina di cui hai appena eseguito il deployment:

Ora che conosci le nozioni di base su come eseguire il deployment di una pagina web con Firebase, passiamo al deployment del nostro esempio di codelab.
4. Esempio di codelab
Puoi clonare il repository del codelab ospitato su GitHub utilizzando il comando riportato di seguito:
$ git clone https://github.com/google/device-access-codelab-web-app.git
In questo repository forniamo esempi in due cartelle separate. La cartella codelab-start contiene i file necessari per iniziare dal punto attuale di questo codelab. La cartella codelab-done contiene una versione completa di questo codelab, con il client e il server Node.js completamente funzionanti.
Utilizzeremo i file della cartella codelab-start in tutto il codelab, ma se ti blocchi in qualsiasi momento, puoi fare riferimento anche alla versione completata del codelab.
File di esempio del codelab
La struttura dei file della cartella codelab-start è la seguente:
public ├───index.html ├───scripts.js ├───style.css firebase.json
La cartella pubblica contiene le pagine statiche della nostra applicazione. firebase.json è responsabile dell'instradamento delle richieste web alla nostra app. Nella versione codelab-done, vedrai anche una directory functions, contenente la logica per il deployment del nostro server proxy (express) su Google Cloud Functions.
Esegui il deployment dell'esempio di codelab
Copia i file da codelab-start nella directory del progetto.
$ firebase deploy
Una volta completato il deployment di Firebase, dovresti essere in grado di visualizzare l'applicazione Codelab:

L'avvio del flusso di autorizzazione richiede le credenziali del partner, che tratteremo nella sezione successiva.
5. Gestione di OAuth
OAuth è lo standard web per la delega dell'accesso, comunemente utilizzato dagli utenti per concedere ad applicazioni di terze parti l'accesso ai dati del proprio account senza condividere le password. Utilizziamo OAuth 2.0 per consentire agli sviluppatori di accedere ai dispositivi degli utenti tramite Device Access.

Specifica l'URI di reindirizzamento
Il primo passaggio del flusso OAuth prevede il passaggio di un insieme di parametri all'endpoint Google OAuth 2.0. Dopo aver ottenuto il consenso dell'utente, i server Google OAuth invieranno una richiesta con un codice di autorizzazione all'URI di reindirizzamento.
Aggiorna la costante SERVER_URI (riga 19) con il tuo URL di hosting in scripts.js:
const SERVER_URI = "https://[GCP-Project-Id].web.app";
Il nuovo deployment dell'app con questa modifica aggiornerà l'URI di reindirizzamento utilizzato per il tuo progetto.
$ firebase deploy
Abilita URI di reindirizzamento
Dopo aver aggiornato l'URI di reindirizzamento nel file di script, devi aggiungerlo anche all'elenco degli URI di reindirizzamento consentiti per l'ID client che hai creato per il tuo progetto. Vai alla pagina delle credenziali in Google Cloud, che elenca tutte le credenziali create per il tuo progetto:

Nell'elenco degli ID client OAuth 2.0, seleziona l'ID client che hai creato nel passaggio Creazione progetto. Aggiungi l'URI di reindirizzamento della tua app all'elenco degli URI di reindirizzamento autorizzati per il tuo progetto.

Prova ad accedere.
Vai all'URL di hosting che hai configurato con Firebase, inserisci le credenziali del partner e fai clic sul pulsante ACCEDI. L'ID client e il client secret sono le credenziali che hai ottenuto da Google Cloud Platform, mentre l'ID progetto proviene dalla console Device Access.

Il pulsante ACCEDI indirizzerà gli utenti al flusso OAuth per la tua azienda, a partire dalla schermata di accesso al loro Account Google. Una volta effettuato l'accesso, agli utenti verrà chiesto di fornire le autorizzazioni al tuo progetto per accedere ai loro dispositivi Nest.

Poiché si tratta di un'app di test, Google emetterà un avviso prima di eseguire un reindirizzamento.

Fai clic su "Avanzate", quindi seleziona "Vai a web.app (non sicura)" per completare il reindirizzamento alla tua app.

In questo modo viene fornito un codice OAuth nell'ambito della richiesta GET in entrata, che l'app scambierà con un token di accesso e un token di aggiornamento.
6. Controllo dei dispositivi
L'app di esempio Device Access utilizza chiamate API REST Smart Device Management per controllare i dispositivi Google Nest. Queste chiamate prevedono il passaggio del token di accesso nell'intestazione di una richiesta GET o POST, insieme a un payload richiesto per determinati comandi.
Abbiamo scritto una funzione generica di richiesta di accesso per gestire queste chiamate. Tuttavia, dovrai fornire l'endpoint corretto, nonché l'oggetto payload, se necessario, a questa funzione.
function deviceAccessRequest(method, call, localpath, payload = null) {...}
- method: tipo di richiesta HTTP (
GEToPOST)) - call: una stringa che rappresenta la nostra chiamata API, utilizzata per indirizzare le risposte (
listDevices,thermostatMode,temperatureSetpoint) - localpath: l'endpoint a cui viene inviata la richiesta, contenente l'ID progetto e l'ID dispositivo (aggiunti dopo
https://smartdevicemanagement.googleapis.com/v1) - payload (*) – Dati aggiuntivi richiesti per la chiamata API (ad esempio, un valore numerico che rappresenta la temperatura per un punto di controllo)
Creeremo controlli UI di esempio (Elenca dispositivi, Imposta modalità, Imposta temperatura) per controllare un termostato Nest:

Questi controlli dell'interfaccia utente chiameranno le funzioni corrispondenti (listDevices(), postThermostatMode(), postTemperatureSetpoint()) da scripts.js. Sono lasciati vuoti per consentirti di implementarli. L'obiettivo è scegliere il metodo/percorso corretto e passare il payload alla funzione deviceAccessRequest(...).
Elenco dispositivi
La chiamata Device Access più semplice è listDevices. Utilizza una richiesta GET e non richiede payload. L'endpoint deve essere strutturato utilizzando projectId. Completa la funzione listDevices() come segue:
function listDevices() {
var endpoint = "/enterprises/" + projectId + "/devices";
deviceAccessRequest('GET', 'listDevices', endpoint);
}
Salva le modifiche e esegui di nuovo il deployment del progetto Firebase con il seguente comando:
$ firebase deploy
Una volta implementata la nuova versione dell'app, prova a ricaricare la pagina e fai clic su ELENCO DISPOSITIVI. In questo modo, l'elenco nella sezione Controllo dispositivo dovrebbe essere compilato e dovresti visualizzare l'ID del termostato:

La selezione dei dispositivi dall'elenco aggiornerà il campo deviceId nel file scripts.js. Per i due controlli successivi, dovremo specificare l'deviceId per il dispositivo specifico che vogliamo controllare.
Controllo del termostato
Nell'API Smart Device Management sono disponibili due tratti per il controllo di base di un termostato Nest. ThermostatMode e TemperatureSetpoint. ThermostatMode imposta la modalità del termostato Nest su una delle quattro possibili modalità: {Off, Heat, Cool, HeatCool}. Dobbiamo quindi fornire la modalità selezionata come parte del payload.
Sostituisci la funzione postThermostatMode() in scripts.js con quanto segue:
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);
}
La funzione successiva, postTemperatureSetpoint(), gestisce l'impostazione della temperatura (in gradi Celsius) per Nest Thermostat. Nel payload possono essere impostati due parametri, heatCelsius e coolCelsius, a seconda della modalità termostato selezionata.
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. Server Node.js (facoltativo)
Complimenti! Hai creato un'applicazione web lato client che può effettuare richieste all'API Smart Device Management da un browser. Per chi vuole sviluppare sul lato server, vogliamo dare il via al vostro lavoro con un server proxy in grado di reindirizzare le richieste dal browser.
Per questo server proxy, utilizzeremo le funzioni cloud Firebase, Node.js ed Express.
Inizializza Cloud Functions
Apri una nuova finestra del terminale, vai alla directory del progetto ed esegui il comando seguente:
$ firebase init functions
Firebase ti porrà una serie di domande per inizializzare le funzioni cloud:
- In quale linguaggio vuoi scrivere le funzioni Cloud Functions? — JavaScript
- Vuoi utilizzare ESLint per rilevare i bug probabili e applicare lo stile? — No
- Vuoi installare le dipendenze con npm ora? — Sì
Verrà inizializzata una cartella functions nel progetto e verranno installate le dipendenze necessarie. Vedrai che la cartella del progetto contiene una directory functions, con un file index.js per definire le nostre funzioni cloud, un file package.json per definire le impostazioni e una directory node_modules per contenere le dipendenze.
Utilizzeremo due librerie npm per creare la funzionalità lato server: express e xmlhttprequest. Devi aggiungere le seguenti voci all'elenco delle dipendenze nel file package.json:
"xmlhttprequest": "^1.8.0", "express": "^4.17.0"
L'esecuzione di npm install dalla directory delle funzioni dovrebbe installare le dipendenze per il tuo progetto:
$ npm install
Se npm riscontra un problema con il download dei pacchetti, puoi provare a salvare xmlhttprequest ed express in modo esplicito con il seguente comando:
$ npm install express xmlhttprequest --save
Esegui l'upgrade al piano Blaze
L'utilizzo del comando firebase deploy richiede l'upgrade al piano Blaze, che a sua volta richiede l'aggiunta di un metodo di pagamento al tuo account. Vai a Panoramica del progetto > Utilizzo e fatturazione e assicurati di selezionare il piano Blaze per il tuo progetto.

Crea il server Express
Un server Express segue un semplice framework per rispondere alle richieste GET e POST in entrata. Abbiamo creato una servlet che ascolta le richieste POST, le trasmette a un URL di destinazione specificato nel payload e risponde con la risposta ricevuta dal trasferimento.
Modifica il file index.js nella directory delle funzioni in modo che abbia il seguente aspetto:
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);
Per indirizzare le richieste al nostro server, dobbiamo modificare le riscritture da firebase.json come segue:
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "/proxy**",
"function": "app"
},{
"source": "**",
"destination": "/index.html"
}
]
}
}
In questo modo, gli URL che iniziano con /proxy verranno indirizzati al nostro server Express, mentre gli altri continueranno a essere indirizzati al nostro index.html.
Chiamate API proxy
Ora che il server è pronto, definiamo un URI proxy in scripts.js in modo che il browser invii le richieste a questo indirizzo:
const PROXY_URI = SERVER_URI + "/proxy";
Poi aggiungi una funzione proxyRequest è scripts.js, che ha la stessa firma della funzione deviceAccessRequest(...), per le chiamate di accesso al dispositivo indiretto.
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();
}
L'ultimo passaggio consiste nel sostituire le chiamate deviceAccessRequest(...) con la funzione proxyRequest(...) nelle funzioni postThermostatMode() e postTemperatureSetpoint() all'interno di scripts.js.
Esegui firebase deploy per aggiornare l'app.
$ firebase deploy
In questo modo, ora hai un server proxy Node.js in esecuzione che utilizza Express su Cloud Functions.
Fornisci le autorizzazioni per Cloud Functions
L'ultimo passaggio consiste nel rivedere le autorizzazioni di accesso per le tue funzioni cloud e assicurarti che la tua applicazione lato client sia in grado di chiamarle.
Da Google Cloud Platform, vai alla scheda Cloud Functions dal menu, quindi seleziona la tua funzione cloud:

Fai clic su Autorizzazioni, poi su Aggiungi membro. Scrivi allUsers nel nuovo campo membro e seleziona Cloud Functions > Cloud Functions Invoker come ruolo. Se fai clic su Salva, viene visualizzato un messaggio di avviso:

Se selezioni Consenti accesso pubblico, la tua applicazione lato client potrà utilizzare la tua funzione cloud.
Congratulazioni, hai completato tutti i passaggi. Ora puoi andare alla tua app web e provare i controlli del dispositivo indirizzati tramite il server proxy.
Passaggi successivi
Stai cercando modi per ampliare le tue competenze su Device Access? Consulta la documentazione sui tratti per scoprire di più sul controllo di altri dispositivi Nest e la procedura di certificazione per scoprire i passaggi per lanciare il tuo prodotto in tutto il mondo.
Migliora le tue competenze con l'app di esempio dell'applicazione web Device Access, dove potrai ampliare la tua esperienza con Codelab e implementare un'applicazione web funzionante per controllare videocamere, campanelli e termostati Nest.