1. Zanim zaczniesz
Jako deweloper Internetu Rzeczy (IoT) możesz tworzyć integracje chmur, które umożliwiają użytkownikom sterowanie urządzeniami za pomocą elementów sterujących w aplikacji Google Home i poleceń głosowych Asystenta.
Integracje między chmurami korzystają z Home Graph, aby dostarczać dane kontekstowe o domu i jego urządzeniach, tworząc logiczną mapę domu. Dzięki temu kontekstowi Asystent może lepiej zrozumieć prośby użytkownika w zależności od jego lokalizacji w domu. Na przykład Home Graph może przechowywać koncepcję salonu, w którym znajdują się różne typy urządzeń różnych producentów, takich jak termostat, lampa, wentylator i odkurzacz.
Wymagania wstępne
- Tworzenie integracji między chmurami – Przewodnik dla deweloperów
Co utworzysz
W tym ćwiczeniu z programowania opublikujesz usługę w chmurze, która zarządza wirtualną inteligentną pralką, a potem utworzysz integrację chmur i połączysz ją z Asystentem.
Czego się nauczysz
- Jak wdrożyć usługę chmurową inteligentnego domu
- Jak połączyć usługę z Asystentem
- Jak publikować zmiany stanu urządzenia w Google
Czego potrzebujesz
- przeglądarka internetowa, np. Google Chrome;
- urządzenie z iOS lub Androidem z zainstalowaną aplikacją Google Home;
- Node.js w wersji 10.16 lub nowszej
- konto rozliczeniowe Google Cloud;
2. Pierwsze kroki
Włączanie Zarządzania aktywnością
Aby korzystać z Asystenta Google, musisz udostępnić Google określone dane o aktywności. Asystent Google potrzebuje tych danych do prawidłowego działania, ale udostępnianie danych nie jest wymagane w przypadku pakietu SDK. Aby udostępniać te dane, utwórz konto Google, jeśli jeszcze go nie masz. Możesz użyć dowolnego konta Google – nie musi to być Twoje konto dewelopera.
Otwórz stronę Zarządzanie aktywnością na koncie Google, którego chcesz używać z Asystentem.
Upewnij się, że te przełączniki są włączone:
- Aktywność w internecie i aplikacjach – pamiętaj też, aby zaznaczyć pole wyboru Uwzględnij historię Chrome i aktywność na stronach, urządzeniach i w aplikacjach, które używają usług Google.
- Informacje o urządzeniu
- Aktywność związana z głosem i dźwiękiem
Tworzenie projektu integracji między chmurami
- Otwórz konsolę dewelopera.
- Kliknij Utwórz projekt, wpisz nazwę projektu i kliknij Utwórz projekt.
Wybierz integrację chmur
W sekcji Cloud-to-cloud (Między chmurami) na stronie Project Home (Strona projektu) w Konsoli programisty kliknij Add cloud-to-cloud integration (Dodaj integrację między chmurami).
Zainstaluj wiersz poleceń Firebase
Interfejs wiersza poleceń Firebase (CLI) umożliwia obsługę aplikacji internetowych lokalnie i wdrażanie ich do hostingu Firebase.
Aby zainstalować interfejs wiersza poleceń, uruchom w terminalu to polecenie npm:
npm install -g firebase-tools
Aby sprawdzić, czy interfejs wiersza poleceń został prawidłowo zainstalowany, uruchom:
firebase --version
Autoryzuj wiersz poleceń Firebase za pomocą swojego konta Google, wykonując:
firebase login
3. Uruchamianie aplikacji startowej
Gdy już skonfigurujesz środowisko programistyczne, możesz wdrożyć projekt startowy, aby sprawdzić, czy wszystko jest prawidłowo skonfigurowane.
Pobieranie kodu źródłowego
Aby pobrać na maszynę programistyczną przykładowy projekt tego ćwiczenia, kliknij ten link:
Możesz też sklonować repozytorium GitHub z poziomu wiersza poleceń:
git clone https://github.com/google-home/smarthome-washer.git
Informacje o projekcie
Projekt startowy zawiera te katalogi podrzędne:
public:
Interfejs użytkownika umożliwiający łatwe sterowanie pralką i monitorowanie jej stanu.functions:
W pełni zaimplementowana usługa w chmurze, która zarządza inteligentną pralką za pomocą Cloud Functions dla Firebase i Bazy danych czasu rzeczywistego Firebase.
Tworzenie projektu Firebase
- Otwórz Firebase.
- Kliknij Utwórz projekt i wpisz nazwę projektu.
- Zaznacz pole wyboru akceptacji i kliknij Dalej. Jeśli nie ma pola wyboru dotyczącego umowy, możesz pominąć ten krok.
- Po utworzeniu projektu Firebase odszukaj jego identyfikator. Kliknij Przegląd projektu, a potem ikonę ustawień > Ustawienia projektu.
- Twój projekt jest widoczny na karcie Ogólne.
Połącz się z Firebase
Przejdź do katalogu washer-start
, a potem skonfiguruj wiersz poleceń Firebase w ramach projektu integracji:
cd washer-start firebase use <firebase-project-id>
Skonfiguruj projekt Firebase
Inicjalizacja projektu Firebase.
firebase init
Wybierz funkcje wiersza poleceń, Baza danych czasu rzeczywistego, Funkcje i funkcję Hosting, która obejmuje Hosting Firebase.
? Which Firebase CLI features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. ❯◉ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance ◯ Firestore: Configure security rules and indexes files for Firestore ◉ Functions: Configure a Cloud Functions directory and its files ◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys ◯ Hosting: Set up GitHub Action deploys ◯ Storage: Configure a security rules file for Cloud Storage ◯ Emulators: Set up local emulators for Firebase products ◯ Remote Config: Configure a template file for Remote Config ◯ Extensions: Set up an empty Extensions manifest
Spowoduje to zainicjowanie niezbędnych interfejsów API i funkcji w projekcie.
Po wyświetleniu odpowiedniej prośby zainicjuj bazę danych Firebase Realtime Database. Możesz użyć domyślnej lokalizacji dla instancji bazy danych.
? It seems like you haven't initialized Realtime Database in your project yet. Do you want to set it up? Yes ? Please choose the location for your default Realtime Database instance: us-central1
Ponieważ używasz kodu projektu podstawowego, wybierz domyślny plik reguł zabezpieczeń i upewnij się, że nie zastąpisz istniejącego pliku reguł bazy danych.
? File database.rules.json already exists. Do you want to overwrite it with the Realtime Database Security Rules for <project-ID>-default-rtdb from the Firebase Console? No
Jeśli ponownie inicjujesz projekt, gdy pojawi się pytanie, czy chcesz zainicjować lub zastąpić bazę kodu, wybierz Zastąp.
? Would you like to initialize a new codebase, or overwrite an existing one? Overwrite
Podczas konfigurowania funkcji użyj plików domyślnych i upewnij się, że nie zastąpisz istniejących plików index.js i package.json w próbnym projekcie.
? What language would you like to use to write Cloud Functions? JavaScript ? Do you want to use ESLint to catch probable bugs and enforce style? No ? File functions/package.json already exists. Overwrite? No ? File functions/index.js already exists. Overwrite? No
Jeśli ponownie inicjujesz projekt, gdy pojawi się pytanie, czy chcesz zainicjować lub zastąpić pliki functions/.gitignore, wybierz Nie.
? File functions/.gitignore already exists. Overwrite? No
? Do you want to install dependencies with npm now? Yes
Na koniec skonfiguruj ustawienia hostingu, aby używać katalogu public
w kodzie projektu, i użyj istniejącego pliku index.html. Gdy pojawi się pytanie o używanie ESLint, wybierz Nie.
? What do you want to use as your public directory? public ? Configure as a single-page app (rewrite all urls to /index.html)? Yes ? Set up automatic builds and deploys with GitHub? No ? File public/index.html already exists. Overwrite? No
Jeśli ESLint zostało przypadkowo włączone, możesz je wyłączyć na 2 sposoby:
- Za pomocą interfejsu graficznego przejdź do folderu
../functions
w ramach projektu, wybierz ukryty plik.eslintrc.js
i usuń go. Nie myl go z elementem o podobnej nazwie.eslintrc.json
. - W wierszu poleceń:
cd functions rm .eslintrc.js
W pliku washer-done/firebase.json
uzupełnij kod:
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
},
"headers": [{
"source" : "**/*.@(js|html)",
"headers" : [ {
"key" : "Cache-Control",
"value" : "max-age=0"
} ]
}],
"functions": [
{
"source": "functions",
"codebase": "default",
"ignore": [
"node_modules",
".git",
"firebase-debug.log",
"firebase-debug.*.log",
"*.local"
]
}
]
}
Wdrażanie w Firebase
Po zainstalowaniu zależności i skonfigurowaniu projektu możesz uruchomić aplikację po raz pierwszy.
firebase deploy
Dane wyjściowe konsoli powinny wyglądać tak:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<firebase-project-id>/overview Hosting URL: https://<firebase-project-id>.web.app
To polecenie wdraża aplikację internetową wraz z kilkoma funkcjami Cloud Functions dla Firebase.
Aby wyświetlić aplikację internetową, otwórz w przeglądarce (https://
) adres URL hostingu. Zobaczysz ten interfejs:
Ten interfejs internetowy reprezentuje platformę innej firmy, która umożliwia wyświetlanie i modyfikowanie stanów urządzenia. Aby rozpocząć wypełnianie bazy danych informacjami o urządzeniach, kliknij Zaktualizuj. Nie zobaczysz żadnych zmian na stronie, ale bieżący stan pralki zostanie zapisany w bazie danych.
Teraz możesz połączyć wdrożony przez siebie serwis chmurowy z Asystentem Google za pomocą Konsoli dewelopera Google Home.
Konfigurowanie projektu w Konsoli deweloperów
Na karcie Tworzenie dodaj Wyświetlaną nazwę interakcji. Ta nazwa będzie widoczna w aplikacji Google Home.
W sekcji Marka aplikacji prześlij plik png
ikony aplikacji o rozmiarze 144 × 144 pikseli i nazwie
.
Aby włączyć łączenie kont, użyj tych ustawień:
Identyfikator klienta |
|
Tajny klucz klienta |
|
Adres URL autoryzacji |
|
Adres URL tokena |
|
W sekcji URL realizacji w chmurze wpisz adres URL funkcji w chmurze, która zapewnia realizację intencji związanych z inteligentnym domem.
https://us-central1-
Aby zapisać konfigurację projektu, kliknij Zapisz, a potem kliknij Dalej: testowanie, aby włączyć testowanie projektu.
Teraz możesz zacząć wdrażać webhooki niezbędne do połączenia stanu urządzenia z Asystentem.
4. Tworzenie pralki
Po skonfigurowaniu integracji możesz dodawać urządzenia i wysyłać dane. Usługa w chmurze musi obsługiwać te intencje:
- Intencje
SYNC
występują, gdy Asystent chce wiedzieć, jakie urządzenia są połączone z użytkownikiem. Jest on wysyłany do Twojej usługi, gdy użytkownik połączy konto. W odpowiedzi należy podać dane JSON wszystkich urządzeń użytkownika i ich możliwości. - Intencją
QUERY
jest, aby Asystent poznał bieżący stan urządzenia. Powinieneś odpowiedzieć ładunkiem JSON z stanem każdego żądanego urządzenia. - Intencje
EXECUTE
występują, gdy Asystent chce sterować urządzeniem w imieniu użytkownika. W odpowiedzi należy podać treść w formacie JSON z informacjami o stanie wykonania na każdym z wybranych urządzeń. - Intencje
DISCONNECT
występują, gdy użytkownik odłączy swoje konto od Asystenta. Należy przestać wysyłać do Asystenta zdarzenia z urządzeń tego użytkownika.
W następnych sekcjach zaktualizujesz funkcje, które zostały wcześniej wdrożone do obsługi tych intencji.
Aktualizowanie odpowiedzi SYNC
Otwórz functions/index.js
, który zawiera kod odpowiadający na żądania Asystenta.
Musisz obsłużyć SYNC
, zwracając metadane i możliwości urządzenia. Zaktualizuj dane JSON w tablicy onSync
, aby zawierały informacje o urządzeniu i zalecane cechy pralki.
index.js
app.onSync((body) => {
return {
requestId: body.requestId,
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',
],
name: {
defaultNames: ['My Washer'],
name: 'Washer',
nicknames: ['Washer'],
},
deviceInfo: {
manufacturer: 'Acme Co',
model: 'acme-washer',
hwVersion: '1.0',
swVersion: '1.0.1',
},
willReportState: true,
attributes: {
pausable: true,
},
}],
},
};
});
Wdrażanie w Firebase
Wdróż zaktualizowane wypełnianie w chmurze za pomocą wiersza poleceń Firebase:
firebase deploy --only functions
Łączenie z Asystentem Google
Aby przetestować integrację między chmurami, musisz połączyć projekt z kontem Google. Umożliwia to testowanie w interfejsach Asystenta Google i aplikacji Google Home, w których użytkownik jest zalogowany na to samo konto.
- Na telefonie otwórz ustawienia Asystenta Google. Pamiętaj, że musisz zalogować się na to samo konto, którego używasz w konsoli.
- Kliknij Asystent Google > Ustawienia > Sterowanie domem (w sekcji Asystent).
- W prawym górnym rogu kliknij ikonę wyszukiwania.
- Aby znaleźć konkretną aplikację testową, wyszukaj ją, używając prefiksu [test].
- Wybierz ten element. Asystent Google uwierzytelnia się w Twojej usłudze i wysyła żądanie
SYNC
, aby Twoja usługa podała listę urządzeń użytkownika.
Otwórz aplikację Google Home i sprawdź, czy widzisz swoją pralkę.
5. Obsługa poleceń i zapytań
Teraz, gdy usługa w chmurze prawidłowo zgłasza Google urządzenie do prania, musisz dodać możliwość żądania stanu urządzenia i wysyłania poleceń.
Obsługa zamiaru QUERY
QUERY
intencja obejmuje zestaw urządzeń. W przypadku każdego urządzenia podaj jego aktualny stan.
W functions/index.js
zmodyfikuj QUERY
, aby przetworzyć listę urządzeń docelowych zawartych w prośbie o intencję.
index.js
app.onQuery(async (body) => {
const {requestId} = body;
const payload = {
devices: {},
};
const queryPromises = [];
const intent = body.inputs[0];
for (const device of intent.payload.devices) {
const deviceId = device.id;
queryPromises.push(queryDevice(deviceId)
.then((data) => {
// Add response to device payload
payload.devices[deviceId] = data;
}
));
}
// Wait for all promises to resolve
await Promise.all(queryPromises);
return {
requestId: requestId,
payload: payload,
};
});
W przypadku każdego urządzenia zawartego w żądaniu zwraca aktualny stan przechowywany w BazaDanychWczasieRzealnym. Zmodyfikuj funkcje queryFirebase
i queryDevice
, aby zwracały dane o stanie pralki.
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,
};
};
const queryDevice = async (deviceId) => {
const data = await queryFirebase(deviceId);
return {
on: data.on,
isPaused: data.isPaused,
isRunning: data.isRunning,
currentRunCycle: [{
currentCycle: 'rinse',
nextCycle: 'spin',
lang: 'en',
}],
currentTotalRemainingTime: 1212,
currentCycleRemainingTime: 301,
};
};
Obsługa zamiaru EXECUTE
Intencją EXECUTE
zarządza poleceniami aktualizowania stanu urządzenia. Odpowiedź zwraca stan każdego polecenia (na przykład SUCCESS
, ERROR
lub PENDING
) oraz nowy stan urządzenia.
W functions/index.js
zmodyfikuj element obsługi EXECUTE
, aby przetworzyć listę cech, które wymagają aktualizacji, oraz zestaw urządzeń docelowych dla każdego polecenia:
index.js
app.onExecute(async (body) => {
const {requestId} = body;
// Execution results are grouped by status
const result = {
ids: [],
status: 'SUCCESS',
states: {
online: true,
},
};
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(
updateDevice(execution, device.id)
.then((data) => {
result.ids.push(device.id);
Object.assign(result.states, data);
})
.catch(() => functions.logger.error('EXECUTE', device.id)));
}
}
}
await Promise.all(executePromises);
return {
requestId: requestId,
payload: {
commands: [result],
},
};
});
W przypadku każdego polecenia i urządzenia docelowego zaktualizuj w Bazadzie danych w czasie rzeczywistym wartości odpowiadające żądanej właściwości. Zmodyfikuj funkcję updateDevice
, aby zaktualizować odpowiednie odwołanie do Firebase i zwrócić zaktualizowany stan urządzenia.
index.js
const updateDevice = async (execution, deviceId) => {
const {params, command} = execution;
let state; let 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 = params.start
? {isRunning: true, isPaused: false}
: {isRunning: false, isPaused: false};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.PauseUnpause':
const data = await queryDevice(deviceId);
state = (data.isPaused === false && data.isRunning === false)
? {isRunning: false, isPaused: false}
: {isRunning: !params.pause, isPaused: params.pause};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
}
return ref.update(state)
.then(() => state);
};
6. Testowanie integracji
Po zaimplementowaniu wszystkich 3 zamierowań możesz przetestować, czy integracja steruje pralką.
Wdrażanie w Firebase
Wdróż zaktualizowane wypełnianie w chmurze za pomocą wiersza poleceń Firebase:
firebase deploy --only functions
Testowanie pralki
Teraz możesz zobaczyć, jak zmienia się wartość, gdy na telefonie użyjesz któregoś z tych poleceń głosowych:
„OK Google, włącz pralkę”
„OK Google, wstrzymaj pranie”
„OK Google, zatrzymaj pralkę”
Możesz też sprawdzić aktualny stan pralki, zadawać pytania.
„OK Google, czy moja pralka jest włączona?”
„OK Google, czy moja pralka działa?”
„OK Google, na którym cyklu jest moja pralka?”
Te zapytania i polecenia możesz wyświetlić w logach, które pojawiają się pod funkcją w sekcji Funkcje w Konsoli Firebase. Więcej informacji o logach Firebase znajdziesz w artykule Zapisywanie i wyświetlanie logów.
Te zapytania i polecenia znajdziesz też w konsoli Google Cloud, gdy klikniesz Logowanie > Eksplorator logów. Więcej informacji o logowaniu w Google Cloud znajdziesz w artykule Dostęp do dzienników zdarzeń za pomocą Cloud Logging.
7. Zgłaszanie zmian do Google
Twoja usługa w chmurze jest w pełni zintegrowana z intencjami inteligentnego domu, co umożliwia użytkownikom kontrolowanie i wysyłanie zapytań dotyczących bieżącego stanu ich urządzeń. W obecnej implementacji brakuje jednak sposobu na to, aby Twoja usługa mogła aktywnie wysyłać do Asystenta informacje o wydarzeniach, np. o zmianach stanu lub obecności urządzenia.
Za pomocą opcji Poproś o synchronizację możesz wysłać prośbę o synchronizację, gdy użytkownicy dodają lub usuwają urządzenia albo gdy zmieniają się możliwości ich urządzeń. Dzięki raportowaniu stanu usługa w chmurze może proaktywnie wysyłać stan urządzenia do Home Graph, gdy użytkownicy fizycznie zmienią stan urządzenia (np. włączą przełącznik światła) lub zmienią stan za pomocą innej usługi.
W tej sekcji dodasz kod, który wywoła te metody z frontendowej aplikacji internetowej.
Włącz interfejs HomeGraph API
Interfejs HomeGraph API umożliwia przechowywanie urządzeń i ich stanów oraz wysyłanie zapytań o te dane w ramach Home Graph użytkownika. Aby korzystać z tego interfejsu API, musisz najpierw otworzyć konsolę Google Cloud i włączyć interfejs HomeGraph API.
W konsoli Google Cloud wybierz projekt, który odpowiada integracji. <project-id>.
Następnie na ekranie Biblioteka interfejsów API dla interfejsu HomeGraph API kliknij Włącz.
Włączanie raportowania stanu
Zapisy w BDB uruchamiają funkcję reportstate
w projekcie startowym. Zaktualizuj funkcję reportstate
w funkcji functions/index.js
, aby rejestrować dane zapisane w bazie danych i publikować je w usłudze Dom Graph za pomocą stanu raportu.
index.js
exports.reportstate = functions.database.ref('{deviceId}').onWrite(
async (change, context) => {
functions.logger.info('Firebase write event triggered Report State');
const snapshot = change.after.val();
const requestBody = {
requestId: 'ff36a3cc', /* Any unique ID */
agentUserId: USER_ID,
payload: {
devices: {
states: {
/* Report the current state of our washer */
[context.params.deviceId]: {
on: snapshot.OnOff.on,
isPaused: snapshot.StartStop.isPaused,
isRunning: snapshot.StartStop.isRunning,
},
},
},
},
};
const res = await homegraph.devices.reportStateAndNotification({
requestBody,
});
functions.logger.info('Report state response:', res.status, res.data);
});
Włącz synchronizację żądań
Odświeżenie ikony w interfejsie internetowym front-endu powoduje uruchomienie funkcji requestsync
w projekcie startowym. Aby wywołać interfejs HomeGraph API, zaimplementuj funkcję requestsync
w funkcji functions/index.js
.
index.js
exports.requestsync = functions.https.onRequest(async (request, response) => {
response.set('Access-Control-Allow-Origin', '*');
functions.logger.info(`Request SYNC for user ${USER_ID}`);
try {
const res = await homegraph.devices.requestSync({
requestBody: {
agentUserId: USER_ID,
},
});
functions.logger.info('Request sync response:', res.status, res.data);
response.json(res.data);
} catch (err) {
functions.logger.error(err);
response.status(500).send(`Error requesting sync: ${err}`);
}
});
Wdrażanie w Firebase
Wdróż zaktualizowany kod za pomocą wiersza poleceń Firebase:
firebase deploy --only functions
Testowanie implementacji
W interfejsie internetowym kliknij przycisk Odśwież i sprawdź, czy w rejestrze konsoli Firebase pojawia się prośba o synchronizację.
Następnie dostosuj atrybuty urządzenia do prania w interfejsie internetowym i kliknij Zaktualizuj. Sprawdź, czy w logach konsoli Firebase widać stan zgłoszony do Google.
8. Gratulacje
Gratulacje! Udało Ci się zintegrować Asystenta z usługą w chmurze na urządzeniu za pomocą integracji chmur.
Więcej informacji
Oto kilka pomysłów, które możesz wdrożyć, aby uzyskać więcej informacji:
- Dodaj tryby i przełączniki na urządzeniu.
- Dodaj do urządzenia więcej obsługiwanych traits.
- Poznaj wykonanie lokalne w inteligentnym domu.
- Aby dowiedzieć się więcej, zapoznaj się z przykładem na GitHubie.
Możesz też dowiedzieć się więcej o testowaniu i przesyłaniu integracji do sprawdzenia, w tym o procesie certyfikacji w celu opublikowania integracji dla użytkowników.