1. Wprowadzenie
Program Device Access udostępnia interfejs Smart Device Management API, czyli interfejs REST API, który umożliwia programistom sterowanie urządzeniami Google Nest z poziomu aplikacji. Użytkownicy muszą wyrazić zgodę na dostęp innych firm do ich urządzeń Nest.

Aby integracja z Device Access zakończyła się sukcesem, musisz wykonać 3 kluczowe kroki:
- Tworzenie projektu – utwórz projekt w Google Cloud Platform i zarejestruj się jako deweloper w Konsoli dostępu do urządzenia.
- Łączenie kont – pozyskuj użytkowników za pomocą procesu łączenia kont i pobieraj kod dostępu. Wymień kod na token dostępu.
- Device Control – wysyłaj żądania do interfejsu Smart Device Management API, aby sterować urządzeniami, wysyłając polecenia z tokenem dostępu.
W tym Codelabs przyjrzymy się szczegółowo, jak działa dostęp do urządzenia. W tym celu utworzymy aplikację internetową obsługującą uwierzytelnianie i wykonującą wywołania interfejsu Smart Device Management API. Omówimy też wdrażanie prostego serwera proxy za pomocą Node.js i Express do kierowania żądań dostępu do urządzenia.
Zanim zaczniesz, warto odświeżyć sobie wiedzę o popularnych technologiach internetowych, których będziemy używać w tym laboratorium, takich jak uwierzytelnianie za pomocą OAuth 2.0 czy tworzenie aplikacji internetowej za pomocą Node.js. Nie są one jednak wymagane.
Potrzebne elementy
- Node.js 8 lub nowsze
- Konto Google z połączonym termostatem Nest
Czego się nauczysz
- Konfigurowanie projektu w Firebase do hostowania statycznych stron internetowych i funkcji w chmurze
- Wysyłanie żądań dostępu do urządzenia za pomocą aplikacji internetowej w przeglądarce
- Tworzenie serwera proxy za pomocą Node.js i Express do kierowania żądań
2. Tworzenie projektu
Aby skonfigurować integrację dostępu do urządzenia, programiści muszą utworzyć projekt Google Cloud Platform (GCP). Identyfikator klienta i tajny klucz klienta wygenerowane w projekcie GCP będą używane w ramach procesu OAuth między aplikacją dewelopera a Google Cloud. Aby uzyskać dostęp do interfejsu Smart Device Management API, deweloperzy muszą też utworzyć projekt w konsoli Device Access.
Google Cloud Platform
Otwórz Google Cloud Platform. Kliknij Utwórz nowy projekt i podaj nazwę projektu. Wyświetli się też identyfikator projektu [GCP-Project-Id] w Google Cloud. Zapisz go, ponieważ użyjemy go podczas konfigurowania Firebase. (W dalszej części tych ćwiczeń z programowania będziemy odwoływać się do tego identyfikatora jako [GCP-Project-Id]).

Pierwszym krokiem jest włączenie w projekcie niezbędnej biblioteki interfejsów API. Otwórz Interfejsy API i usługi > Biblioteka i wyszukaj Smart Device Management API. Musisz włączyć ten interfejs API, aby autoryzować projekt do wysyłania żądań do wywołań interfejsu API dostępu do urządzenia.

Zanim przejdziemy do tworzenia danych logowania OAuth, musimy skonfigurować ekran zgody OAuth dla naszego projektu. Otwórz Interfejsy API i usługi > Ekran zgody OAuth. W polu Typ użytkownika wybierz zewnętrzny. Aby przejść do następnego ekranu, podaj nazwę i adres e-mail pomocy dotyczącej aplikacji oraz informacje kontaktowe dewelopera. Gdy pojawi się prośba o podanie użytkowników testowych, na tym etapie podaj adres e-mail powiązany z urządzeniami.
Po skonfigurowaniu ekranu zgody OAuth otwórz Interfejsy API i usługi > Dane logowania. Kliknij +Utwórz dane logowania i wybierz Identyfikator klienta OAuth. Jako typ aplikacji wybierz Aplikacja internetowa.

Podaj nazwę klienta i kliknij UTWÓRZ. Autoryzowane źródło JavaScript i autoryzowany identyfikator URI przekierowania dodamy później. Po zakończeniu tego procesu pojawią się [Client-Id] i [Client-Secret] powiązane z tym klientem OAuth 2.0.

Konsola dostępu do urządzenia
Otwórz konsolę dostępu do urządzenia. Jeśli nie korzystasz jeszcze z Konsoli dostępu do urządzenia, zobaczysz Warunki korzystania z usługi i prośbę o uiszczenie opłaty rejestracyjnej w wysokości 5 USD.
Utwórz nowy projekt i nadaj mu nazwę. W następnym oknie podaj [Client-Id] otrzymany w poprzednim kroku z GCP.

Włączenie zdarzeń i wykonanie pozostałych kroków tworzenia projektu spowoduje przejście na stronę główną projektu. [Project-Id] będzie widoczny pod nazwą, którą nadano projektowi.

Zanotuj [Project-Id], ponieważ będziemy go używać podczas wysyłania żądań do interfejsu Smart Device Management API.
3. Konfiguracja Firebase
Firebase umożliwia deweloperom szybkie i łatwe wdrażanie aplikacji internetowych. Na potrzeby integracji z dostępem do urządzenia będziemy tworzyć aplikację internetową po stronie klienta, korzystając z Firebase.
Tworzenie projektu Firebase
Otwórz konsolę Firebase. Kliknij Dodaj projekt, a następnie wybierz projekt utworzony w kroku Tworzenie projektu. Spowoduje to utworzenie projektu w Firebase, który zostanie połączony z projektem GCP [GCP-Project-Id].
Po pomyślnym utworzeniu projektu w Firebase powinien wyświetlić się ten ekran:

Instalowanie narzędzi Firebase
Firebase udostępnia zestaw narzędzi wiersza poleceń do tworzenia i wdrażania aplikacji. Aby zainstalować te narzędzia, otwórz nowe okno terminala i uruchom to polecenie. Spowoduje to zainstalowanie narzędzi Firebase na całym świecie.
$ npm i -g firebase-tools
Aby sprawdzić, czy narzędzia Firebase zostały zainstalowane prawidłowo, sprawdź informacje o wersji.
$ firebase --version
Za pomocą polecenia logowania możesz zalogować się w narzędziach wiersza poleceń Firebase przy użyciu konta Google.
$ firebase login
Inicjowanie projektu hostingu
Gdy uda Ci się zalogować, zainicjuj projekt hostingu dla aplikacji internetowej. W terminalu przejdź do folderu, w którym chcesz utworzyć projekt, i uruchom to polecenie:
$ firebase init hosting
Firebase zada Ci kilka pytań, aby pomóc Ci rozpocząć pracę z projektem hostingowym:
- Wybierz opcję Użyj istniejącego projektu.
- Wybierz domyślny projekt w Firebase dla tego katalogu – Wybierz ***[GCP-Project-Id]***
- Jakiego katalogu publicznego chcesz używać? – Publiczny
- Skonfigurować jako aplikację jednostronicową? – Tak.
- Konfigurowanie automatycznych kompilacji i wdrażania za pomocą GitHuba – Nie
Gdy projekt zostanie zainicjowany, możesz go wdrożyć w Firebase za pomocą tego polecenia:
$ firebase deploy
Firebase przeskanuje Twój projekt i wdroży niezbędne pliki w hostingu w chmurze.

Gdy otworzysz adres URL hostingu w przeglądarce, powinna wyświetlić się wdrożona strona:

Znasz już podstawy wdrażania strony internetowej za pomocą Firebase, więc teraz przejdźmy do wdrażania przykładowej aplikacji z ćwiczeń z programowania.
4. Przykładowe ćwiczenie z programowania
Możesz sklonować repozytorium z ćwiczeniami hostowane na GitHubie, używając tego polecenia:
$ git clone https://github.com/google/device-access-codelab-web-app.git
W tym repozytorium udostępniamy przykłady w 2 oddzielnych folderach. Folder codelab-start zawiera pliki potrzebne do rozpoczęcia pracy w tym momencie ćwiczenia. codelab-done zawiera pełną wersję tego Codelabu z w pełni funkcjonalnym klientem i serwerem node.js.
W tym laboratorium będziemy używać plików z folderu codelab-start. Jeśli jednak w dowolnym momencie poczujesz, że utknąłeś, możesz też skorzystać z wersji codelab-done.
Przykładowe pliki ćwiczeń z programowania
Struktura plików w folderze codelab-start jest taka:
public ├───index.html ├───scripts.js ├───style.css firebase.json
Folder publiczny zawiera statyczne strony naszej aplikacji. firebase.json odpowiada za kierowanie żądań internetowych do naszej aplikacji. W wersji codelab-done zobaczysz też katalog functions, który zawiera logikę serwera proxy (express) do wdrożenia w funkcjach Google Cloud.
Wdrażanie przykładowych ćwiczeń z programowania
Skopiuj pliki z folderu codelab-start do katalogu projektu.
$ firebase deploy
Po zakończeniu wdrażania Firebase powinna być widoczna aplikacja Codelab:

Rozpoczęcie procesu uwierzytelniania wymaga danych logowania partnera, o których opowiemy w następnej sekcji.
5. Obsługa OAuth
OAuth to standard internetowy służący do delegowania dostępu, powszechnie używany przez użytkowników do przyznawania aplikacjom innych firm dostępu do informacji o ich kontach bez udostępniania haseł. Używamy protokołu OAuth 2.0, aby umożliwić deweloperom dostęp do urządzeń użytkowników za pomocą Device Access.

Określanie identyfikatora URI przekierowania
Pierwszy krok przepływu OAuth polega na przekazaniu zestawu parametrów do punktu końcowego OAuth 2.0 Google. Po uzyskaniu zgody użytkownika serwery Google OAuth wyślą żądanie z kodem autoryzacji do Twojego identyfikatora URI przekierowania.
Zaktualizuj stałą SERVER_URI (wiersz 19) o swój adres URL hostingu w scripts.js:
const SERVER_URI = "https://[GCP-Project-Id].web.app";
Ponowne wdrożenie aplikacji z tą zmianą spowoduje zaktualizowanie identyfikatora URI przekierowania używanego w projekcie.
$ firebase deploy
Włączanie identyfikatora URI przekierowania
Po zaktualizowaniu identyfikatora URI przekierowania w pliku skryptów musisz też dodać go do listy dozwolonych identyfikatorów URI przekierowania dla identyfikatora klienta utworzonego na potrzeby projektu. Otwórz stronę danych logowania w Google Cloud Platform, na której znajdziesz listę wszystkich danych logowania utworzonych w Twoim projekcie:

Na liście Identyfikatory klienta OAuth 2.0 wybierz identyfikator klienta utworzony w kroku Tworzenie projektu. Dodaj identyfikator URI przekierowania aplikacji do listy Autoryzowane identyfikatory URI przekierowania w projekcie.

Spróbuj się zalogować!
Otwórz adres URL hostingu skonfigurowany w Firebase, wpisz dane logowania partnera i kliknij przycisk ZALOGUJ SIĘ. Identyfikator klienta i klucz tajny klienta to dane logowania uzyskane z Google Cloud Platform, a identyfikator projektu pochodzi z Konsoli dostępu do urządzenia.

Przycisk ZALOGUJ SIĘ przeprowadzi użytkowników przez proces OAuth w Twojej firmie, zaczynając od ekranu logowania na konto Google. Po zalogowaniu użytkownicy zostaną poproszeni o przyznanie Twojemu projektowi uprawnień dostępu do ich urządzeń Nest.

Ponieważ jest to aplikacja testowa, przed przekierowaniem Google wyświetli ostrzeżenie.

Kliknij „Zaawansowane”, a potem „Otwórz web.app (niebezpieczne)”, aby dokończyć przekierowanie do aplikacji.

W ramach przychodzącego żądania GET otrzymasz kod OAuth, który aplikacja wymieni na token dostępu i token odświeżania.
6. Sterowanie urządzeniami
Przykładowa aplikacja Device Access używa wywołań interfejsu Smart Device Management REST API do sterowania urządzeniami Google Nest. W przypadku tych wywołań token dostępu jest przekazywany w nagłówku żądania GET lub POST wraz z ładunkiem wymaganym w przypadku niektórych poleceń.
Aby obsługiwać te wywołania, napisaliśmy ogólną funkcję żądania dostępu. Musisz jednak podać prawidłowy punkt końcowy, a w razie potrzeby także obiekt ładunku.
function deviceAccessRequest(method, call, localpath, payload = null) {...}
- method – typ żądania HTTP (
GETlubPOST)); - call – ciąg znaków reprezentujący wywołanie interfejsu API, używany do kierowania odpowiedzi (
listDevices,thermostatMode,temperatureSetpoint); - localpath – punkt końcowy, do którego wysyłane jest żądanie, zawierający identyfikator projektu i identyfikator urządzenia (dołączony po znaku
https://smartdevicemanagement.googleapis.com/v1). - payload (*) – dodatkowe dane wymagane do wywołania interfejsu API (np. wartość liczbowa reprezentująca temperaturę dla punktu nastawy);
Utworzymy przykładowe elementy sterujące interfejsu (List Devices, Set Mode, Set Temp) do sterowania termostatem Nest:

Te elementy interfejsu będą wywoływać odpowiednie funkcje (listDevices(), postThermostatMode(), postTemperatureSetpoint()) z scripts.js. Pozostawiamy je puste, aby umożliwić Ci ich wdrożenie. Chodzi o wybranie prawidłowej metody lub ścieżki i przekazanie ładunku do funkcji deviceAccessRequest(...).
Wyświetlanie listy urządzeń
Najprostsze wywołanie dostępu do urządzenia to listDevices. Używa żądania GET i nie wymaga ładunku. Punkt końcowy musi być skonstruowany za pomocą projectId. Uzupełnij funkcję listDevices() w ten sposób:
function listDevices() {
var endpoint = "/enterprises/" + projectId + "/devices";
deviceAccessRequest('GET', 'listDevices', endpoint);
}
Zapisz zmiany i ponownie wdróż projekt w Firebase za pomocą tego polecenia:
$ firebase deploy
Po wdrożeniu nowej wersji aplikacji spróbuj ponownie wczytać stronę i kliknij LISTA URZĄDZEŃ. Powinna się pojawić lista w sekcji Sterowanie urządzeniem, na której powinien być widoczny identyfikator termostatu:

Wybór urządzeń z listy spowoduje zaktualizowanie pola deviceId w pliku scripts.js. W przypadku 2 kolejnych elementów sterujących musimy określić deviceId dla konkretnego urządzenia, którym chcemy sterować.
Sterowanie termostatem
Interfejs Smart Device Management API udostępnia 2 cechy do podstawowego sterowania termostatem Nest. ThermostatMode i TemperatureSetpoint. ThermostatMode ustawia tryb termostatu Nest na jeden z 4 możliwych trybów: {Off, Heat, Cool, HeatCool}. Wybrany tryb musimy następnie podać w ładunku.
Zastąp funkcję postThermostatMode() w pliku scripts.js tym kodem:
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);
}
Kolejna funkcja, postTemperatureSetpoint(), służy do ustawiania temperatury (w stopniach Celsjusza) na termostacie Nest. W ładunku można ustawić 2 parametry: heatCelsius i coolCelsius, w zależności od wybranego trybu termostatu.
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. Serwer Node.js (opcjonalnie)
Gratulacje! Masz aplikację internetową po stronie klienta, która może wysyłać żądania do interfejsu Smart Device Management API z przeglądarki. Osobom, które chcą tworzyć tagi po stronie serwera, udostępniamy serwer proxy, który może przekierowywać żądania z przeglądarki.
W przypadku tego serwera proxy użyjemy funkcji Cloud Functions Firebase, Node.js i Express.
Inicjowanie Cloud Functions
Otwórz nowe okno terminala, przejdź do katalogu projektu i uruchom to polecenie:
$ firebase init functions
Firebase zada Ci kilka pytań, aby zainicjować funkcje w chmurze:
- W jakim języku chcesz pisać funkcje w Cloud Functions? – JavaScript
- Czy chcesz używać ESLint do wykrywania prawdopodobnych błędów i wymuszania stylu? – Nie
- Czy chcesz teraz zainstalować zależności za pomocą npm? – Tak.
Spowoduje to zainicjowanie w projekcie folderu functions oraz zainstalowanie niezbędnych zależności. W folderze projektu znajdziesz katalog funkcji z plikiem index.js, w którym zdefiniowane są funkcje Cloud Functions, plik package.json z ustawieniami oraz katalog node_modules z zależnościami.
Do utworzenia funkcji po stronie serwera użyjemy 2 bibliotek środowiska npm: express i xmlhttprequest. Do listy zależności w pliku package.json musisz dodać te wpisy:
"xmlhttprequest": "^1.8.0", "express": "^4.17.0"
Następnie uruchomienie polecenia npm install w katalogu funkcji powinno zainstalować zależności projektu:
$ npm install
Jeśli npm ma problem z pobieraniem pakietów, możesz spróbować zapisać xmlhttprequest i express w sposób jawny za pomocą tego polecenia:
$ npm install express xmlhttprequest --save
Przejście na abonament Blaze
Użycie polecenia firebase deploy wymaga przejścia na abonament Blaze, co wiąże się z dodaniem do konta formy płatności. Otwórz Przegląd projektu > Użycie i rozliczenia i upewnij się, że dla projektu wybrano plan Blaze.

Tworzenie serwera Express
Serwer Express korzysta z prostej struktury, aby odpowiadać na przychodzące żądania GET i POST. Utworzyliśmy servlet, który nasłuchuje żądań POST, przesyła je do docelowego adresu URL określonego w ładunku i odpowiada odpowiedzią otrzymaną z przesyłania.
Zmodyfikuj plik index.js w katalogu funkcji, aby wyglądał tak:
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);
Aby kierować żądania do naszego serwera, musimy dostosować przekierowania z firebase.json w ten sposób:
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "/proxy**",
"function": "app"
},{
"source": "**",
"destination": "/index.html"
}
]
}
}
Spowoduje to przekierowanie adresów URL zaczynających się od /proxy na nasz serwer Express, a pozostałe będą nadal kierowane na nasz serwer index.html.
Wywołania interfejsu API proxy
Serwer jest już gotowy, więc zdefiniujmy identyfikator URI serwera proxy w scripts.js, aby przeglądarka mogła wysyłać żądania na ten adres:
const PROXY_URI = SERVER_URI + "/proxy";
Następnie dodaj funkcję proxyRequest is scripts.js, która ma taką samą sygnaturę jak funkcja deviceAccessRequest(...), w przypadku wywołań pośrednich dostępu do urządzenia.
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();
}
Ostatnim krokiem jest zastąpienie wywołań deviceAccessRequest(...) funkcją proxyRequest(...) w funkcjach postThermostatMode() i postTemperatureSetpoint() w pliku scripts.js.
Uruchom firebase deploy, aby zaktualizować aplikację.
$ firebase deploy
Masz teraz działający serwer proxy Node.js korzystający z Express w Cloud Functions.
Przyznawanie uprawnień do funkcji w Cloud Functions
Ostatnim krokiem jest sprawdzenie uprawnień dostępu do funkcji w chmurze i upewnienie się, że aplikacja po stronie klienta będzie mogła je wywoływać.
W Google Cloud Platform otwórz kartę Cloud Functions w menu, a następnie wybierz funkcję w Cloud:

Kliknij Uprawnienia, a potem Dodaj członka. Wpisz allUsers w nowym polu członka i jako rolę wybierz Cloud Functions > Wywołujący funkcje Cloud Functions. Kliknięcie Zapisz spowoduje wyświetlenie komunikatu ostrzegawczego:

Jeśli wybierzesz opcję Zezwól na dostęp publiczny, aplikacja po stronie klienta będzie mogła korzystać z funkcji w Cloud Functions.
Gratulacje – wszystkie kroki zostały wykonane. Możesz teraz przejść do aplikacji internetowej i wypróbować sterowanie urządzeniami kierowane przez serwer proxy.
Następne kroki
Chcesz poszerzyć swoją wiedzę na temat dostępu do urządzenia? Więcej informacji o sterowaniu innymi urządzeniami Nest znajdziesz w dokumentacji cech, a o procesie certyfikacji – w artykule opisującym kroki, które musisz wykonać, aby wprowadzić swój produkt na rynek.
Rozwiń swoje umiejętności dzięki przykładowej aplikacji internetowej Device Access, w której wykorzystasz zdobytą wiedzę z Codelabs i wdrożysz działającą aplikację internetową do sterowania kamerami, dzwonkami i termostatami Nest.