1. Zanim zaczniesz
Jako deweloper internetu rzeczy możesz tworzyć działania w inteligentnym domu, które umożliwiają użytkownikom sterowanie urządzeniami za pomocą sterowania dotykowego w aplikacji Google Home oraz poleceń głosowych przy użyciu Asystenta.
Działania związane z inteligentnym domem korzystają z wykresu domowego, aby dostarczać dane kontekstowe o domu i jego urządzeniach, tworząc logiczną mapę domu. Dzięki temu Asystent będzie mógł lepiej zrozumieć, czego domaga się użytkownik, względem jego lokalizacji w domu. Na przykład Home Graph może przechowywać informacje o salonie, w których znajdują się różne rodzaje urządzeń różnych producentów, takie jak termostat, lampa, wentylator czy odkurzacz.
Wymagania wstępne
- Tworzenie akcji w inteligentnym domu – przewodnik dla deweloperów
Co utworzysz
W ramach tego ćwiczenia w programie opublikujesz usługę w chmurze, która będzie zarządzać wirtualną pralką, a następnie utworzysz akcję inteligentnego domu i połączysz ją z Asystentem.
Czego się nauczysz
- Jak wdrożyć usługę w chmurze do inteligentnego domu
- Jak połączyć usługę z Asystentem
- Jak opublikować zmiany stanu urządzenia w Google
Czego potrzebujesz
- Przeglądarka, np. Google Chrome.
- urządzenie z iOS lub Androidem i zainstalowaną aplikacją Google Home;
- Node.js w wersji 10.16 lub nowszej.
- konto rozliczeniowe Google Cloud;
2. Wprowadzenie
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 wymóg udostępniania danych nie dotyczy tylko pakietu SDK. Aby udostępnić te dane, musisz utworzyć konto Google. Możesz użyć dowolnego konta Google – nie musi to być konto dewelopera.
Otwórz stronę Zarządzanie aktywnością na koncie Google, którego chcesz używać z Asystentem.
Sprawdź, czy te przełączniki są włączone:
- Aktywność w internecie i aplikacjach – zaznacz też pole wyboru Uwzględnij historię Chrome i aktywność na stronach, urządzeniach i w aplikacjach, które używają usług Google.
- Informacje z urządzenia
- Aktywność związana z głosem i dźwiękiem
Tworzenie projektu w Actions
- Otwórz Konsolę programisty Actions on Google.
- Kliknij Nowy projekt, wpisz nazwę projektu i kliknij UTWÓRZ PROJEKT.
Wybierz aplikację Inteligentny dom
Na ekranie Przegląd w Konsoli Actions wybierz Inteligentny dom.
Aby przejść do konsoli projektu, wybierz kartę Inteligentny dom i kliknij Rozpocznij tworzenie.
Instalowanie interfejsu wiersza poleceń Firebase
Interfejs wiersza poleceń Firebase (CLI) umożliwia udostępnianie aplikacji internetowych lokalnie i wdrażanie ich w 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 polecenie:
firebase --version
Autoryzuj interfejs wiersza poleceń Firebase na swoim koncie Google, uruchamiając polecenie:
firebase login
3. Uruchamianie aplikacji startowej
Po skonfigurowaniu środowiska programistycznego możesz wdrożyć projekt początkowy, aby sprawdzić, czy wszystko jest skonfigurowane prawidłowo.
Pobieranie kodu źródłowego
Kliknij poniższy link, aby pobrać na komputerze przykładowy program do przykładowego ćwiczenia:
Możesz też sklonować repozytorium GitHub z wiersza poleceń:
git clone https://github.com/google-home/smarthome-washer.git
Informacje o projekcie
Projekt startowy zawiera te podkatalogi:
public:
Interfejs frontendu umożliwiający łatwe kontrolowanie i monitorowanie stanu inteligentnej pralki.functions:
W pełni wdrożona usługa w chmurze, która umożliwia zarządzanie inteligentną pralką za pomocą Cloud Functions dla Firebase i Bazy danych czasu rzeczywistego Firebase.
Łączenie z Firebase
Przejdź do katalogu washer-start
, a następnie skonfiguruj interfejs wiersza poleceń Firebase w projekcie Actions:
cd washer-start firebase use <project-id>
Konfigurowanie projektu Firebase
Zainicjuj projekt Firebase.
firebase init
Wybierz funkcje interfejsu wiersza poleceń, Bazę danych czasu rzeczywistego, Funkcje i funkcję Hosting obejmującą 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 wymaganych interfejsów API i funkcji w projekcie.
Po wyświetleniu monitu zainicjuj Bazę danych czasu rzeczywistego. Możesz użyć domyślnej lokalizacji 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 początkowego, wybierz domyślny plik reguł zabezpieczeń i upewnij się, że nie zastąpisz istniejącego pliku z regułami 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, w odpowiedzi na pytanie, czy chcesz zainicjować, czy 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 nie zastępuj istniejących plików index.js ani package.json w przykładowym 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, w odpowiedzi na pytanie, czy chcesz zainicjować czy zastąpić funkcje/.gitignore, wybierz Nie.
? File functions/.gitignore already exists. Overwrite? No
? Do you want to install dependencies with npm now? Yes
Na koniec skonfiguruj konfigurację Hostingu tak, aby używała katalogu public
w kodzie projektu i używała istniejącego pliku index.html. W odpowiedzi na pytanie o korzystanie z 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ł włączony przypadkowo, można go wyłączyć na 2 sposoby:
- W interfejsie GUI przejdź do folderu
../functions
w projekcie, wybierz ukryty plik.eslintrc.js
i usuń go. Nie pomyl go z podobną nazwą.eslintrc.json
. - Przy użyciu wiersza poleceń:
cd functions rm .eslintrc.js
Aby upewnić się, że konfiguracja Firebase jest prawidłowa, skopiuj plik firebase.json
z katalogu app-done
do katalogu app-start
, zastępując plik w pliku app-start
.
W katalogu app-start
:
cp -vp ../app-done/firebase.json .
Wdrażanie w Firebase
Po zainstalowaniu zależności i skonfigurowaniu projektu możesz po raz pierwszy uruchomić aplikację.
firebase deploy
Powinny pojawić się te dane wyjściowe konsoli:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<project-id>/overview Hosting URL: https://<project-id>.web.app
To polecenie wdraża aplikację internetową i kilka funkcji Cloud Functions dla Firebase.
Otwórz w przeglądarce URL hostowania (https://<project-id>.web.app
), aby wyświetlić aplikację internetową. Zobaczysz ten interfejs:
Ten interfejs internetowy reprezentuje platformę firmy zewnętrznej do wyświetlania i modyfikowania stanów urządzeń. Aby rozpocząć wypełnianie bazy danych informacjami o urządzeniu, kliknij AKTUALIZUJ. Na stronie nie pojawią się żadne zmiany, ale bieżący stan pralki będzie przechowywany w bazie danych.
Teraz możesz połączyć wdrożoną z Asystenta Google usługę w chmurze za pomocą Konsoli Actions.
Konfigurowanie projektu w Konsoli Actions
W sekcji Przegląd > Utwórz działanie wybierz Dodaj działania. Wpisz adres URL funkcji w Cloud Functions, która realizuje intencje inteligentnego domu, i kliknij Zapisz.
https://us-central1-<project-id>.cloudfunctions.net/smarthome
Na karcie Programowanie > Wywołanie dodaj wyświetlaną nazwę działania i kliknij Zapisz. Ta nazwa będzie widoczna w aplikacji Google Home.
Żeby włączyć łączenie kont, w menu nawigacyjnym po lewej stronie wybierz opcję Programowanie > Łączenie kont. Użyj tych ustawień łączenia kont:
Identyfikator klienta |
|
Tajny klucz klienta |
|
Adres URL autoryzacji |
|
URL tokena |
|
Kliknij Zapisz, aby zapisać konfigurację łączenia kont, a potem kliknij Przetestuj, aby włączyć testowanie w projekcie.
Przekierujemy Cię do Symulatora. Jeśli nie widzisz opcji „Testuj teraz włączony”, kliknij Resetuj test, aby sprawdzić, czy testowanie jest włączone.
Teraz możesz zacząć implementować webhooki niezbędne do połączenia stanu urządzenia z Asystentem.
4. Utwórz pralkę
Po skonfigurowaniu akcji możesz dodawać urządzenia i wysyłać dane. Usługa w chmurze musi obsługiwać te intencje:
- Intencja
SYNC
występuje, gdy Asystent chce sprawdzić, jakie urządzenia połączył użytkownik. Jest ona wysyłana do Twojej usługi, gdy użytkownik połączy konto. W odpowiedzi musisz przesłać ładunek JSON dotyczący wszystkich urządzeń użytkownika i ich możliwości. - Intencja
QUERY
występuje, gdy Asystent chce poznać bieżący stan urządzenia. W odpowiedzi należy przesłać ładunek JSON zawierający informacje o stanie każdego żądanego urządzenia. - Intencja
EXECUTE
występuje, gdy Asystent chce sterować urządzeniem w imieniu użytkownika. W odpowiedzi należy przesłać ładunek JSON zawierający informacje o stanie wykonania każdego żądanego urządzenia. - Intencja
DISCONNECT
występuje, gdy użytkownik odłącza swoje konto od Asystenta. Musisz przestać wysyłać do Asystenta zdarzenia z urządzeń tego użytkownika.
W kolejnych sekcjach zaktualizujesz wdrożone wcześniej funkcje na potrzeby obsługi tych intencji.
Zaktualizuj odpowiedź SYNC
Otwórz aplikację functions/index.js
, która zawiera kod odpowiadający na prośby od Asystenta.
Musisz obsłużyć intencję SYNC
, zwracając metadane i funkcje urządzenia. Zaktualizuj plik JSON w tablicy onSync
, aby uwzględnić informacje o urządzeniu i zalecane cechy pralki do ubrań.
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óż zaktualizowaną realizację w chmurze za pomocą interfejsu wiersza poleceń Firebase:
firebase deploy --only functions
Łączenie z Asystentem Google
Aby przetestować działanie inteligentnego domu, musisz połączyć swój projekt z kontem Google. Umożliwi Ci to testowanie na platformach Asystenta Google i w aplikacji Google Home po zalogowaniu się na to samo konto.
- Na telefonie otwórz ustawienia Asystenta Google. Pamiętaj, aby zalogować się na to samo konto co w konsoli.
- Wybierz Asystent Google > Ustawienia > Sterowanie domem (w sekcji Asystent).
- Kliknij ikonę wyszukiwania w prawym górnym rogu.
- Wyszukaj swoją aplikację testową, korzystając z prefiksu [test].
- Wybierz ten element. Asystent Google uwierzytelni się w Twojej usłudze i wyśle żądanie
SYNC
, prosząc usługę o podanie listy urządzeń dla użytkownika.
Otwórz aplikację Google Home i sprawdź, czy widzisz pralkę.
5. Obsługa poleceń i zapytań
Teraz gdy Twoja usługa w chmurze prawidłowo zgłasza pralkę do Google, musisz dodać możliwość żądania stanu urządzenia i wysyłania poleceń.
Obsługa intencji QUERY
Intencja QUERY
obejmuje zbiór urządzeń. W odpowiedzi na każde urządzenie należy podać bieżący stan.
W functions/index.js
zmodyfikuj moduł obsługi QUERY
, aby przetworzyć listę urządzeń docelowych zawartych w żądaniu intencji.
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,
};
});
Dla każdego urządzenia w żądaniu zwraca bieżący stan zapisany w bazie danych czasu rzeczywistego. Zaktualizuj funkcje queryFirebase
i queryDevice
, aby zwracać 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 intencji EXECUTE
Intencja EXECUTE
obsługuje polecenia do 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
edytuj moduł obsługi EXECUTE
, aby przetworzyć listę cech, które wymagają aktualizacji, oraz zbiór 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],
},
};
});
Dla każdego polecenia i urządzenia docelowego zaktualizuj wartości w Bazie danych czasu rzeczywistego, które odpowiadają żądanej cechy. Zmodyfikuj funkcję updateDevice
, aby zaktualizować odpowiednie odniesienie 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 = {isRunning: params.start};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.PauseUnpause':
state = {isPaused: params.pause};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
}
return ref.update(state)
.then(() => state);
};
6. Testowanie działania
Po zaimplementowaniu wszystkich 3 intencji możesz sprawdzić, czy akcja kontroluje pralkę.
Wdrażanie w Firebase
Wdróż zaktualizowaną realizację w chmurze za pomocą interfejsu wiersza poleceń Firebase:
firebase deploy --only functions
Testowanie pralki
Teraz możesz sprawdzić tę zmianę po wypróbowaniu na telefonie dowolnego z tych poleceń głosowych:
„OK Google, włącz pralkę”.
„OK Google, wstrzymaj pralkę”.
„OK Google, zatrzymaj pralkę”.
Możesz też zadać pytania, aby sprawdzić bieżący stan pralki.
„OK Google, czy moja pralka jest włączona?”
„OK Google, czy moja pralka działa?”
„OK Google, jaki jest cykl pralki?”
Te zapytania i polecenia możesz wyświetlać w dziennikach wyświetlanych w obszarze funkcji w sekcji Funkcje 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, klikając Logowanie > Eksplorator logów. Więcej informacji o logowaniu w Google Cloud znajdziesz w artykule Uzyskiwanie dostępu do dzienników zdarzeń za pomocą Cloud Logging.
7. Zgłaszanie aktualizacji do Google
Usługa w chmurze jest w pełni zintegrowana z intencjami inteligentnego domu, dzięki czemu użytkownicy mogą kontrolować bieżący stan swoich urządzeń i wysyłać dotyczące ich zapytania. Jednak w dalszym ciągu nie ma możliwości, aby usługa aktywnie wysyłała do Asystenta informacje o zdarzeniach, np. o zmianach obecności lub stanu urządzenia.
Za pomocą opcji Poproś o synchronizację możesz wysłać nowe żądanie synchronizacji, gdy użytkownicy dodają lub usuwają urządzenia albo gdy zmienią się możliwości ich urządzeń. Dzięki stanowi raportu usługa w chmurze może proaktywnie wysyłać informacje o stanie urządzenia do Home Graph, gdy użytkownik fizycznie zmieni stan urządzenia (np. włączy przełącznik światła) lub zmieni go przy użyciu innej usługi.
W tej sekcji dodasz kod wywołujący te metody z aplikacji internetowej frontendu.
Włączanie interfejsu HomeGraph API
HomeGraph API umożliwia przechowywanie i zapytania dotyczące urządzeń oraz ich stanów w Home Graph. Aby używać tego interfejsu API, musisz najpierw otworzyć konsolę Google Cloud i włączyć interfejs HomeGraph API.
W konsoli Google Cloud wybierz projekt zgodny z działaniami <project-id>.
. Następnie na ekranie Biblioteka API interfejsu HomeGraph kliknij Włącz.
Włącz stan raportu
Zapisy w Bazie danych czasu rzeczywistego aktywują funkcję reportstate
w projekcie startowym. Zaktualizuj funkcję reportstate
w narzędziu functions/index.js
, aby przechwytywać dane zapisane w bazie danych i opublikować je w Home Graph w ramach 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łączanie synchronizacji żądań
Odświeżenie ikony w interfejsie internetowym frontendu powoduje uruchomienie funkcji requestsync
w projekcie startowym. Zaimplementuj funkcję requestsync
w tabeli functions/index.js
, aby wywoływać interfejs API HomeGraph.
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ą interfejsu wiersza poleceń Firebase:
firebase deploy --only functions
Testowanie implementacji
Kliknij przycisk Odśwież w interfejsie internetowym i sprawdź, czy w dzienniku konsoli Firebase widzisz żądanie synchronizacji.
Następnie dostosuj atrybuty pralki w interfejsie internetowym frontendu i kliknij Aktualizuj. Sprawdź, czy w dziennikach konsoli Firebase widzisz zmianę stanu zgłoszona do Google.
8. Gratulacje
Gratulacje! Udało Ci się zintegrować Asystenta z usługą w chmurze na urządzeniu za pomocą akcji inteligentnego domu.
Więcej informacji
Oto kilka pomysłów, które możesz wykorzystać, aby zwiększyć swoją skuteczność:
- Dodaj do urządzenia modes i przełączniki.
- Dodaj do urządzenia więcej obsługiwanych cech.
- Poznaj lokalne wdrożenie inteligentnego 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 akcji do sprawdzenia, w tym o procesie certyfikacji w celu publikowania go użytkownikom.