1. Wstęp
Program dostępu do urządzenia udostępnia interfejs Smart Device Management API, czyli interfejs API typu REST, który umożliwia deweloperom sterowanie urządzeniami Google Nest z poziomu ich aplikacji. Użytkownicy muszą wyrazić zgodę na dostęp innych firm do swoich urządzeń Nest.
Skuteczna integracja z dostępem do urządzenia składa się z 3 kluczowych kroków:
- Tworzenie projektu – utwórz projekt w Google Cloud Platform i zarejestruj się jako programista w Konsoli dostępu do urządzenia.
- Łączenie kont – zachęć użytkowników do łączenia kont i pozyskania kodu dostępu. Wymień kod na token dostępu.
- Sterowanie urządzeniami – wysyłaj żądania do interfejsu Smart Device Management API, aby sterować urządzeniami, wysyłając polecenia z tokenem dostępu.
W tym ćwiczeniu z programowania szczegółowo omówimy, jak działa dostęp do urządzenia – utworzymy aplikację internetową, która obsługuje uwierzytelnianie i wywołuje wywołania interfejsu Smart Device Management API. Zamierzamy też wdrożyć prosty serwer proxy wykorzystujący Node.js i Express, aby kierować żądania dostępu do urządzenia.
Zanim zaczniesz, warto przypomnieć sobie popularne technologie internetowe używane w tym ćwiczeniu z programowania, takie jak uwierzytelnianie za pomocą protokołu OAuth 2.0 lub tworzenie aplikacji internetowej za pomocą Node.js. Nie są to jednak wymagania wstępne.
Potrzebne elementy
- Node.js w wersji 8 lub nowszej
- Konto Google z połączonym urządzeniem Nest Thermostat
Czego się nauczysz
- Konfigurowanie projektu Firebase hostującego statyczne strony internetowe i funkcje w Cloud Functions
- Wydawanie żądań dostępu do urządzenia za pomocą aplikacji internetowej w przeglądarce
- Tworzenie serwera proxy z użyciem Node.js i Express do kierowania żądań
2. Tworzenie projektu
Aby skonfigurować integrację dostępu do urządzenia, deweloperzy muszą utworzyć projekt Google Cloud Platform (GCP). W ramach procesu OAuth między aplikacją dewelopera a Google Cloud będą używane identyfikatory klienta i klucz klienta wygenerowane w projekcie GCP. Deweloperzy muszą też otworzyć konsolę dostępu urządzenia, aby utworzyć projekt i uzyskać dostęp do interfejsu Smart Device Management API.
Google Cloud Platform
Otwórz Google Cloud Platform. Kliknij Utwórz nowy projekt i podaj jego nazwę. Będzie też widoczny identyfikator projektu [GCP-Project-Id] dla Google Cloud. Zapisz go, ponieważ będziemy go używać podczas konfiguracji Firebase. (W tym ćwiczeniu z programowania będziemy określać ten identyfikator jako [GCP-Project-Id]).
Najpierw włącz niezbędną bibliotekę interfejsów API w projekcie. Kliknij Interfejsy API i usługi > Biblioteka, a następnie wyszukaj interfejs Smart Device Management API. Musisz włączyć ten interfejs API, aby autoryzować swój projekt do wysyłania żądań do wywołań interfejsu Device Access API.
Zanim przejdziemy do tworzenia danych logowania OAuth, musimy skonfigurować w naszym projekcie ekran zgody OAuth. Otwórz Interfejsy API i usługi > Ekran zgody OAuth. Jako Typ użytkownika wybierz external. Podaj nazwę i adres e-mail pomocy w sprawie aplikacji, a także informacje kontaktowe dewelopera. Gdy pojawi się pytanie o użytkowników testowych, podaj na tym etapie adresy e-mail połączonych urządzeń.
Gdy skonfigurujesz ekran 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. Później dodamy autoryzowane źródło JavaScript i identyfikator URI autoryzowanego przekierowania. Zakończenie tego procesu spowoduje wyświetlenie identyfikatorów [Client-Id] i [Client-Secret] powiązanych z tym klientem OAuth 2.0.
Konsola dostępu do urządzenia
Otwórz konsolę dostępu do urządzenia. Jeśli wcześniej nie korzystałeś(-aś) z Konsoli dostępu do urządzenia, zobaczysz Warunki korzystania z usługi i opłatę rejestracyjną w wysokości 5 USD.
Utwórz nowy projekt i nadaj mu nazwę. W następnym oknie podaj identyfikator [Client-Id] otrzymany od GCP w poprzednim kroku.
Jeśli włączysz zdarzenia i zakończysz tworzenie projektu, otworzy się jego strona główna. Twój [Project-Id] będzie widoczny pod nazwą projektu.
Zapisz swój [Project-Id], ponieważ będziemy go używać podczas wysyłania żądań do interfejsu Smart Device Management API.
3. Konfiguracja Firebase
Firebase zapewnia programistom szybki i łatwy sposób wdrażania aplikacji internetowych. Będziemy tworzyć za pomocą Firebase aplikację internetową po stronie klienta na potrzeby integracji dostępu do urządzenia.
Utwórz projekt Firebase
Otwórz konsolę Firebase. Kliknij Dodaj projekt i wybierz projekt utworzony w kroku Tworzenie projektu. Spowoduje to utworzenie projektu Firebase, który zostanie połączony z Twoim projektem GCP [GCP-Project-Id].
Po utworzeniu projektu Firebase powinien pojawić się ten ekran:
Zainstaluj narzędzia Firebase
Firebase udostępnia zestaw narzędzi interfejsu wiersza poleceń do skompilowania i wdrożenia 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 są prawidłowo zainstalowane, sprawdź informacje o wersji.
$ firebase --version
Możesz zalogować się w narzędziach wiersza poleceń Firebase za pomocą konta Google za pomocą polecenia logowania.
$ firebase login
Inicjowanie projektu Hostingu
Gdy możesz się zalogować, następnym krokiem jest zainicjowanie hostowanego projektu dla aplikacji internetowej. W terminalu przejdź do folderu, w którym chcesz utworzyć projekt, i uruchom to polecenie:
$ firebase init hosting
Firebase zada Ci zestaw pytań, aby rozpocząć pracę z hostingiem:
- Wybierz opcję – Użyj istniejącego projektu.
- Wybierz domyślny projekt Firebase dla tego katalogu – wybierz***[GCP-Project-Id]***
- Co ma być Twoim katalogiem publicznym? – Publiczny
- Skonfigurować aplikację jako aplikację na jednej stronie? — Tak
- Skonfigurować automatyczne kompilacje i wdrożenia za pomocą GitHuba? — Nie
Po zainicjowaniu projektu możesz wdrożyć go w Firebase za pomocą tego polecenia:
$ firebase deploy
Firebase przeskanuje Twój projekt i wdroży niezbędne pliki do hostingu w chmurze.
Gdy otworzysz w przeglądarce adres URL Hostingu, powinna pojawić się wdrożona właśnie strona:
Znasz już podstawy wdrażania stron internetowych za pomocą Firebase, więc czas wdrożyć nasz przykładowy program Codelabs.
4. Przykładowe ćwiczenia z programowania
Możesz skopiować repozytorium ćwiczeń z programowania hostowane na GitHubie za pomocą tego polecenia:
$ git clone https://github.com/google/device-access-codelab-web-app.git
W tym repozytorium przykłady znajdują się w 2 osobnych folderach. Folder codelab-start
zawiera pliki potrzebne do rozpoczęcia ćwiczenia od bieżącego punktu ćwiczenia. Folder codelab-done
zawiera pełną wersję tego ćwiczenia z programowania oraz w pełni funkcjonalnego klienta i serwera Node.js.
W tym ćwiczeniu z programowania będziemy korzystać z plików z folderu codelab-start
, ale jeśli w jakimś momencie napotkasz problemy, możesz też skorzystać z wersji stworzonej z programowania.
Przykładowe pliki ćwiczeń z programowania
Struktura pliku z folderem 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
widoczny jest też katalog functions
zawierający logikę wdrażania serwera proxy (ekspresowego) w funkcjach Google Cloud.
Wdrażanie przykładowego ćwiczenia z programowania
Skopiuj pliki z codelab-start
do katalogu projektu.
$ firebase deploy
Po wdrożeniu Firebase powinna pojawić się aplikacja Codelab:
Aby rozpocząć proces uwierzytelniania, wymagane są dane logowania partnera, które omówimy w następnej sekcji.
5. Obsługa protokołu OAuth
OAuth to internetowy standard przekazywania dostępu, często używany przez użytkowników do przyznawania aplikacjom innych firm dostępu do informacji o swoich kontach bez konieczności udostępniania hasła. Używamy protokołu OAuth 2.0, aby umożliwić deweloperom dostęp do urządzeń użytkowników przez dostęp do urządzeń.
Podaj identyfikator URI przekierowania
Pierwszy krok procesu OAuth obejmuje przekazanie zestawu parametrów do punktu końcowego Google OAuth 2.0. Po uzyskaniu zgody użytkownika serwery Google OAuth wysyłają żądanie z kodem autoryzacji do identyfikatora URI przekierowania.
Zaktualizuj stałą SERVER_URI
(wiersz 19) własnym adresem URL hostingu w polu 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łącz identyfikator 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 w Twoim projekcie. W Google Cloud Platform otwórz stronę danych logowania. Zobaczysz tam 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 stronę Hostingu skonfigurowaną w Firebase, wpisz swoje dane logowania do partnera i kliknij przycisk ZALOGUJ SIĘ. Identyfikator klienta i tajny klucz klienta to dane logowania uzyskane z Google Cloud Platform. Identyfikator projektu pochodzi z Konsoli dostępu do urządzenia.
Przycisk ZALOGUJ SIĘ umożliwia użytkownikom przejście przez proces OAuth na potrzeby Twojej firmy, począwszy od ekranu logowania na konto Google. Po zalogowaniu się użytkownicy zostaną poproszeni o przyznanie w projekcie uprawnień dostępu do urządzeń Nest.
Ponieważ jest to tylko przykładowa aplikacja, przed przekierowaniem użytkownika Google wyśle ostrzeżenie.
Kliknij „Zaawansowane”, a następnie wybierz „Otwórz stronę web.app (niebezpieczna)”, aby dokończyć przekierowywanie do aplikacji.
Spowoduje to udostępnienie kodu OAuth jako części przychodzącego żądania GET, które aplikacja wymieni na token dostępu i token odświeżania.
6. Sterowanie urządzeniem
Przykładowa aplikacja do obsługi urządzeń Google Nest używa wywołań interfejsu API typu REST Smart Device Management do zarządzania urządzeniami. Wywołania te polegają na przekazaniu tokena dostępu w nagłówku żądania GET lub POST razem z ładunkiem wymaganym dla niektórych poleceń.
Opracowaliśmy ogólną funkcję żądania dostępu do obsługi tych wywołań. Musisz jednak podać w tej funkcji prawidłowy punkt końcowy oraz w razie potrzeby obiekt ładunku.
function deviceAccessRequest(method, call, localpath, payload = null) {...}
- metoda – typ żądania HTTP (
GET
lubPOST)
) - 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 urządzenia (dołączane po
https://smartdevicemanagement.googleapis.com/v1
) - ładunek (*) – dodatkowe dane wymagane do wywołania interfejsu API (np. wartość liczbowa reprezentująca temperaturę nastawy).
W interfejsie stworzymy przykładowe elementy sterujące (wyświetlaj listę urządzeń, tryb, ustaw temperaturę), by sterować urządzeniem Nest Thermostat:
Te elementy sterujące interfejsu będą wywoływać odpowiednie funkcje (listDevices()
, postThermostatMode()
, postTemperatureSetpoint()
) z poziomu scripts.js
. Są puste, więc musisz je zaimplementować. Celem jest wybranie prawidłowej metody i ścieżki oraz przekazanie ładunku do funkcji deviceAccessRequest(...)
.
Wyświetlanie listy urządzeń
Najprostsze wywołanie w aplikacji Device Access to listDevices
. Wykorzystuje żądanie GET
i nie wymaga ładunku. Punkt końcowy musi mieć strukturę projectId
. Wypełnij funkcję listDevices()
w następujący sposób:
function listDevices() { var endpoint = "/enterprises/" + projectId + "/devices"; deviceAccessRequest('GET', 'listDevices', endpoint); }
Zapisz zmiany i wdróż projekt Firebase ponownie za pomocą tego polecenia:
$ firebase deploy
Po wdrożeniu nowej wersji aplikacji odśwież stronę i kliknij LISTA URZĄDZEŃ. Powinna pojawić się lista w sekcji Sterowanie urządzeniem, na której powinien znajdować się identyfikator termostatu:
Wybranie 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 chcesz sterować.
Sterowanie termostatem
W interfejsie Smart Device Management API dostępne są 2 cechy podstawowych funkcji sterowania urządzeniem Nest Thermostat. ThermostatMode i TemperatureSetpoint. Tryb termostatu włącza tryb urządzenia Nest Thermostat w jednym z czterech dostępnych: {Off, Heat, Cool, HeatCool}. Następnie musimy udostępnić wybrany tryb jako część ładunku.
Zastąp funkcję postThermostatMode()
w pliku scripts.js
tym:
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); }
Następna funkcja, postTemperatureSetpoint()
, obsługuje ustawianie temperatury (w stopniach Celsjusza) na urządzeniu Nest Thermostat. W zależności od wybranego trybu termostatu można ustawić 2 parametry: heatCelsius
i coolCelsius
.
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 utworzoną po stronie klienta aplikację internetową, która może wysyłać żądania do interfejsu Smart Device Management API z poziomu przeglądarki. Osoby, które chcą tworzyć strony po stronie serwera, mogą zacząć od serwera proxy, który może przekierowywać żądania z przeglądarki.
W przypadku tego serwera proxy użyjemy funkcji Firebase Cloud Functions, 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 zestaw pytań, aby zainicjować funkcje w Cloud Functions:
- W jakim języku chcesz pisać funkcje w Cloud Functions? – JavaScript
- Czy chcesz używać ESLint, aby wychwytywać prawdopodobne błędy i egzekwować styl? — Nie
- Czy chcesz teraz zainstalować zależności przy użyciu npm? — Tak
Spowoduje to zainicjowanie folderu functions
w projekcie oraz zainstalowanie niezbędnych zależności. Zobaczysz, że folder projektu zawiera katalog funkcji z plikiem index.js służącym do definiowania naszych funkcji w chmurze, plikiem package.json do zdefiniowania ustawień i katalogiem node_modules zawierającym zależności.
Do stworzenia funkcji po stronie serwera użyjemy 2 bibliotek 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 npm instalacji z katalogu funkcji powinno zainstalować zależności w projekcie:
$ npm install
Jeśli npm wystąpi problem z pobieraniem pakietów, możesz spróbować zapisać żądanie xmlhttprequest i wyraźnie określić to polecenie:
$ npm install express xmlhttprequest --save
Przejdź na abonament Blaze
Użycie polecenia firebase deploy
wymaga przejścia na abonament Blaze, co wymaga dodania formy płatności do konta. Otwórz Omówienie projektu > Wykorzystanie i płatności i wybierz abonament Blaze dla swojego projektu.
Tworzenie serwera Express
Serwer Express korzysta z prostej struktury do odpowiadania na przychodzące żądania GET
i POST
. Stworzyliśmy serwlet, który nasłuchuje żądań POST
, przesyła je do docelowego adresu URL określonego w ładunku i odpowiada z odpowiedzią otrzymaną z transferu.
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 przekierować żądania do naszego serwera, musimy zmienić przepisy dotyczące modyfikacji 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 ekspresowy, a pozostałe adresy będą nadal przesyłane do index.html
.
Wywołania interfejsu Proxy API
Skoro serwer jest gotowy, określmy w scripts.js
identyfikator URI serwera proxy, aby nasza przeglądarka mogła wysyłać żądania na ten adres:
const PROXY_URI = SERVER_URI + "/proxy";
Następnie dodaj funkcję proxyRequest
, która ma ten sam podpis co funkcja deviceAccessRequest(...)
, to scripts.js
na potrzeby pośrednich wywołań 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 obiekcie scripts.js
.
Uruchom firebase deploy
, aby zaktualizować aplikację.
$ firebase deploy
Dzięki temu masz teraz uruchomiony serwer proxy Node.js za pomocą Express w Cloud Functions.
Przyznawanie uprawnień funkcji w Cloud Functions
Ostatnim krokiem jest sprawdzenie uprawnień dostępu do funkcji w Cloud Functions i upewnienie się, że aplikacja po stronie klienta będzie mogła je wywoływać.
W Google Cloud Platform otwórz kartę Cloud Functions i wybierz swoją funkcję w Cloud Functions:
Kliknij Uprawnienia, a następnie Dodaj użytkownika. W polu nowego użytkownika wpisz atrybut allUsers, a jako rolę wybierz Cloud Functions > Wywołujący funkcje w Cloud Functions. Kliknięcie Zapisz spowoduje wyświetlenie komunikatu z ostrzeżeniem:
Wybranie opcji Zezwól na dostęp publiczny umożliwi aplikacjom po stronie klienta korzystanie z funkcji w Cloud Functions.
Gratulacje! Udało Ci się wykonać wszystkie czynności. Możesz teraz otworzyć aplikację internetową i skorzystać z opcji sterowania urządzeniami kierowanymi przez Twój serwer proxy.
Dalsze kroki
Szukasz sposobów na poszerzenie wiedzy o dostępie do urządzenia? Przeczytaj dokumentację dotyczącą cech, aby dowiedzieć się więcej o sterowaniu innymi urządzeniami Nest, oraz o procesie certyfikacji, aby dowiedzieć się, jak wprowadzić swój produkt na rynek.
Pogłębiaj swoje umiejętności i poznaj przykładową aplikację internetową Dostęp do urządzenia, w której wykorzystasz doświadczenie z programowania i wdrożysz działającą aplikację internetową do sterowania kamerami, dzwonkami i termostatami Nest.