Poprawianie i zabezpieczanie integracji między chmurami

1. Zanim zaczniesz

Integracje między chmurami używają typów urządzeń, aby poinformować Asystenta Google, jakiej gramatyki używać na danym urządzeniu. Cechy urządzenia określają możliwości danego typu urządzenia. Urządzenie dziedziczy stany wszystkich atrybutów urządzenia dodanych do integracji.

dc8dce0dea87cd5c.png

Aby dostosować funkcje urządzeń użytkowników, możesz połączyć dowolne obsługiwane cechy z wybranym typem urządzenia. Jeśli chcesz wdrożyć w swoich działaniach cechy niestandardowe, które nie są obecnie dostępne w schemacie urządzenia, cechy TrybyPrzełączniki umożliwiają sterowanie określonymi ustawieniami za pomocą zdefiniowanej przez Ciebie nazwy.

Oprócz podstawowych funkcji sterowania zapewnianych przez typy i cechy interfejs Smart Home API oferuje dodatkowe funkcje, które zwiększają wygodę użytkowania. Odpowiedzi na błędy zawierają szczegółowe informacje o użytkowniku, gdy intencja nie powiedzie się. Weryfikacja przez drugiego użytkownika rozszerza te odpowiedzi i zapewnia dodatkową ochronę wybranej przez Ciebie cechy urządzenia. Wysyłając określone odpowiedzi na błędy w blokach wyzwań wydawanych przez Asystenta, integracja między chmurami może wymagać dodatkowego autoryzowania, aby wykonać polecenie.

Wymagania wstępne

Co utworzysz

W tym ćwiczeniu z programowania wprowadzisz gotową integrację inteligentnego domu z Firebase, a potem dowiesz się, jak dodać do inteligentnej pralki cechy niestandardowe, takie jak rozmiar załadunku i tryb turbo. Wdrożysz też raportowanie błędów i wyjątków oraz nauczysz się wymagać potwierdzenia słownego włączenia pralki za pomocą weryfikacji dodatkowego użytkownika.

Czego się nauczysz

  • Jak dodać cechy trybów i przełączników do integracji
  • Jak zgłaszać błędy i wyjątki
  • Jak przeprowadzić dodatkową weryfikację użytkownika

Czego potrzebujesz

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

  1. Otwórz konsolę dewelopera.
  2. Kliknij Utwórz projekt, wpisz nazwę projektu i kliknij Utwórz projekt.

Nazwa projektu

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).

Dodawanie integracji 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

Tworzenie projektu Firebase

  1. Otwórz Firebase.
  2. Kliknij Utwórz projekt i wpisz nazwę projektu.
  3. Zaznacz pole wyboru akceptacji i kliknij Dalej. Jeśli nie ma pola wyboru dotyczącego umowy, możesz pominąć ten krok.
    Utwórz projekt Firebase
  4. Po utworzeniu projektu Firebase odszukaj jego identyfikator. Kliknij Przegląd projektu, a potem ikonę ustawień > Ustawienia projektu.
    Otwieranie ustawień projektu
  5. Twój projekt jest widoczny na karcie Ogólne.
    Ogólne ustawienia projektu

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 Twoim działaniom. <firebase-project-id>.Następnie na ekranie Biblioteka interfejsów API dla interfejsu HomeGraph API kliknij Włącz.

ee198858a6eac112.png

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:

...lub możesz sklonować repozytorium GitHub z poziomu wiersza poleceń:

git clone https://github.com/google-home/smarthome-traits.git

Rozpakuj pobrany plik ZIP.

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.

Udostępnione rozwiązanie w chmurze obejmuje te funkcje w usłudze index.js:

  • fakeauth: punkt końcowy autoryzacji do łączenia kont
  • faketoken: punkt końcowy tokena do łączenia kont
  • smarthome: punkt końcowy realizacji intencji w ramach inteligentnego domu
  • reportstate: wywołuje interfejs Home Graph API po zmianie stanu urządzenia.
  • requestsync: umożliwia aktualizacje na urządzeniu użytkownika bez konieczności ponownego łączenia konta.

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.jspackage.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:

  1. 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.
  2. W wierszu poleceń:
    cd functions
    rm .eslintrc.js
    

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://<firebase-project-id>.web.app) adres URL hostingu. Zobaczysz ten interfejs:

5845443e94705557.png

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 musisz połączyć wdrożony przez siebie serwis w chmurze z Asystentem Google za pomocą Konsoli dla deweloperów.

Konfigurowanie projektu w Konsoli deweloperów

Na karcie Tworzenie dodaj Wyświetlaną nazwę interakcji. Ta nazwa będzie widoczna w aplikacji Google Home.

Dodawanie wyświetlanej nazwy

W sekcji Marka aplikacji prześlij plik png ikony aplikacji o rozmiarze 144 × 144 pikseli i nazwie .png.

Dodawanie ikony aplikacji

Aby włączyć łączenie kont, użyj tych ustawień:

Identyfikator klienta

ABC123

Tajny klucz klienta

DEF456

Adres URL autoryzacji

https://us-central1-
.cloudfunctions.net/fakeauth

Adres URL tokena

https://us-central1-
.cloudfunctions.net/faketoken

Aktualizacja adresów URL służących do łączenia kont

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--cloudfunctions.net/smarthome

Dodawanie adresu URL funkcji w Cloud Functions

Aby zapisać konfigurację projektu, kliknij Zapisz, a potem kliknij Dalej: testowanie, aby włączyć testowanie projektu.

Testowanie integracji z chmury do chmury

Teraz możesz zacząć wdrażać webhooki niezbędne do połączenia stanu urządzenia z Asystentem.

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.

  1. Na telefonie otwórz ustawienia Asystenta Google. Pamiętaj, że musisz zalogować się na to samo konto, którego używasz w konsoli.
  2. Kliknij Asystent Google > Ustawienia > Sterowanie domem (w sekcji Asystent).
  3. W prawym górnym rogu kliknij ikonę wyszukiwania.
  4. Aby znaleźć konkretną aplikację testową, wyszukaj ją, używając prefiksu [test].
  5. 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ę.

ae252220753726f6.png

Sprawdź, czy możesz sterować pralką za pomocą poleceń głosowych w aplikacji Google Home. Powinieneś też zobaczyć zmianę stanu urządzenia w interfejsie internetowym usługi w chmurze.

Po wdrożenie podstawowej pralki możesz dostosować tryby dostępne na urządzeniu.

4. Dodawanie trybów

Właściwość action.devices.traits.Modes umożliwia urządzeniu ustawienie dowolnej liczby ustawień dla danego trybu, z których można wybrać tylko jedno. Dodasz do pralki tryb, który określi rozmiar ładunku: mały, średni lub duży.

Aktualizacja odpowiedzi SYNC

Musisz dodać informacje o nowej cesze do odpowiedzi SYNC w sekcji functions/index.js. Te dane są dostępne w tablicy traits i obiekcie attributes, jak pokazano w tym fragmencie kodu.

index.js

app.onSync(body => {
  return {
    requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    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',
          // Add Modes trait
          'action.devices.traits.Modes',
        ],
        name: { ... },
        deviceInfo: { ... },
        attributes: {
          pausable: true,
          //Add availableModes
          availableModes: [{
            name: 'load',
            name_values: [{
              name_synonym: ['load'],
              lang: 'en',
            }],
            settings: [{
              setting_name: 'small',
              setting_values: [{
                setting_synonym: ['small'],
                lang: 'en',
              }]
            }, {
              setting_name: 'medium',
              setting_values: [{
                setting_synonym: ['medium'],
                lang: 'en',
              }]
            }, {
              setting_name: 'large',
              setting_values: [{
                setting_synonym: ['large'],
                lang: 'en',
              }]
            }],
            ordered: true,
          }],
        },
      }],
    },
  };
});

Dodawanie nowych poleceń o zamiarze WYKONANIE

W intencji EXECUTE dodaj polecenie action.devices.commands.SetModes, jak pokazano w tym fragmencie kodu.

index.js

const updateDevice = async (execution,deviceId) => {
  const {params,command} = execution;
  let state, 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;
    // Add SetModes command
    case 'action.devices.commands.SetModes':
      state = {load: params.updateModeSettings.load};
      ref = firebaseRef.child(deviceId).child('Modes');
      break;
}

Aktualizowanie odpowiedzi funkcji QUERY

Następnie zaktualizuj odpowiedź QUERY, aby zgłosić aktualny stan pralki.

Dodaj zaktualizowane zmiany do funkcji queryFirebasequeryDevice, aby uzyskać stan zapisany w Baza danych w czasie rzeczywistym.

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,
    // Add Modes snapshot
    load: snapshotVal.Modes.load,
  };
}

const queryDevice = async (deviceId) => {
  const data = await queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{ ... }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
    // Add currentModeSettings
    currentModeSettings: {
      load: data.load,
    },
  };
};

Aktualizowanie stanu raportu

Na koniec zaktualizuj funkcję reportstate, aby przekazywać do Graph Home informacje o bieżącym ustawieniu prania.

index.js

const requestBody = {
  requestId: 'ff36a3cc', /* Any unique ID */
  agentUserId: USER_ID,
  payload: {
    devices: {
      states: {
        /* Report the current state of your washer */
        [context.params.deviceId]: {
          on: snapshot.OnOff.on,
          isPaused: snapshot.StartStop.isPaused,
          isRunning: snapshot.StartStop.isRunning,
          // Add currentModeSettings
          currentModeSettings: {
            load: snapshot.Modes.load,
          },
        },
      },
    },
  },
};

Wdrażanie w Firebase

Aby wdrożyć zaktualizowaną integrację, uruchom to polecenie:

firebase deploy --only functions

Po zakończeniu wdrażania przejdź do interfejsu internetowego i na pasku narzędzi kliknij przycisk Odśwież ae8d3b25777a5e30.png. Spowoduje to wysłanie żądania synchronizacji, aby Asystent otrzymał zaktualizowane dane odpowiedzi SYNC.

bf4f6a866160a982.png

Teraz możesz wydać polecenie, aby ustawić tryb pralki, na przykład:

„OK Google, ustaw pranie na dużą ilość”.

Dodatkowo możesz zadawać pytania dotyczące pralki, takie jak:

„OK Google, ile jest prania?”

5. Dodawanie przełączników

Właściwość action.devices.traits.Toggles reprezentuje nazwane aspekty urządzenia, które mają stan prawda lub fałsz, np. czy pralka jest w trybie turbo.

Aktualizacja odpowiedzi SYNC

W odpowiedzi na SYNC musisz dodać informacje o nowej właściwości urządzenia. Pojawi się on w tablicy traits i obiekcie attributes, jak pokazano w tym fragmencie kodu.

index.js

app.onSync(body => {
  return {
    requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    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',
          'action.devices.traits.Modes',
          // Add Toggles trait
          'action.devices.traits.Toggles',
        ],
        name: { ... },
        deviceInfo: { ... },
        attributes: {
          pausable: true,
          availableModes: [{
            name: 'load',
            name_values: [{
              name_synonym: ['load'],
              lang: 'en'
            }],
            settings: [{ ... }],
            ordered: true,
          }],
          //Add availableToggles
          availableToggles: [{
            name: 'Turbo',
            name_values: [{
              name_synonym: ['turbo'],
              lang: 'en',
            }],
          }],
        },
      }],
    },
  };
});

Dodawanie nowych poleceń o zamiarze EKSEKWUJ

W intencji EXECUTE dodaj polecenie action.devices.commands.SetToggles, jak pokazano w tym fragmencie kodu.

index.js

const updateDevice = async (execution,deviceId) => {
  const {params,command} = execution;
  let state, 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;
    case 'action.devices.commands.SetModes':
      state = {load: params.updateModeSettings.load};
      ref = firebaseRef.child(deviceId).child('Modes');
      break;
    // Add SetToggles command
    case 'action.devices.commands.SetToggles':
      state = {Turbo: params.updateToggleSettings.Turbo};
      ref = firebaseRef.child(deviceId).child('Toggles');
      break;
  }

Aktualizowanie odpowiedzi funkcji QUERY

Na koniec musisz zaktualizować odpowiedź QUERY, aby zgłosić tryb turbo pralki. Dodaj zaktualizowane zmiany do funkcji queryFirebasequeryDevice, aby uzyskać stan przełącznika zgodnie z danymi przechowywanymi w bazie danych w czasie rzeczywistym.

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,
    load: snapshotVal.Modes.load,
    // Add Toggles snapshot
    Turbo: snapshotVal.Toggles.Turbo,
  };
}

const queryDevice = async (deviceId) => {
  const data = queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{ ... }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
    currentModeSettings: {
      load: data.load,
    },
    // Add currentToggleSettings
    currentToggleSettings: {
      Turbo: data.Turbo,
    },
  };
};

Aktualizowanie stanu raportu

Na koniec zaktualizuj funkcję reportstate, aby przekazywała do Home Graph informacje o tym, czy pralka jest ustawiona na tryb turbo.

index.js

const requestBody = {
  requestId: 'ff36a3cc', /* Any unique ID */
  agentUserId: USER_ID,
  payload: {
    devices: {
      states: {
        /* Report the current state of your washer */
        [context.params.deviceId]: {
          on: snapshot.OnOff.on,
          isPaused: snapshot.StartStop.isPaused,
          isRunning: snapshot.StartStop.isRunning,
          currentModeSettings: {
            load: snapshot.Modes.load,
          },
          // Add currentToggleSettings
          currentToggleSettings: {
            Turbo: snapshot.Toggles.Turbo,
          },
        },
      },
    },
  },
};

Wdrażanie w Firebase

Aby wdrożyć zaktualizowane funkcje, uruchom to polecenie:

firebase deploy --only functions

Po zakończeniu wdrażania kliknij przycisk Odśwież ae8d3b25777a5e30.png w interfejsie internetowym, aby wywołać synchronizację żądań.

Możesz teraz wydać polecenie, aby pralka przeszła w tryb turbo, mówiąc:

„OK Google, włącz turbo w pralce”

Możesz też sprawdzić, czy pralka jest już w trybie turbo, pytając:

„OK Google, czy moja pralka jest w trybie turbo?”

6. Zgłaszanie błędów i wyjątków

Obsługa błędów w ramach integracji chmur umożliwia zgłaszanie użytkownikom problemów, które powodują niepowodzenie odpowiedzi EXECUTE i QUERY. Powiadomienia zwiększają wygodę użytkowników podczas interakcji z urządzeniem inteligentnym i integracją.

W przypadku niepowodzenia żądania EXECUTE lub QUERY integracja powinna zwrócić kod błędu. Jeśli na przykład chcesz wywołać błąd, gdy użytkownik spróbuje uruchomić pralkę z otwartą pokrywą, odpowiedź EXECUTE będzie wyglądać tak:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "456"
        ],
        "status": "ERROR",
        "errorCode": "deviceLidOpen"
      }
    ]
  }
}

Teraz, gdy użytkownik poprosi o włączenie pralki, Asystent odpowie:

„Pokrywa pralki jest otwarta. Zamknij ją i spróbuj ponownie”.

Wyjątki są podobne do błędów, ale wskazują, kiedy alert jest powiązany z poleceniem, co może blokować jego wykonanie. Wyjątek może zawierać powiązane informacje za pomocą atrybutu StatusReport, takiego jak poziom naładowania baterii lub ostatni stan. Kody wyjątku nieblokującego są zwracane z kodem stanu SUCCESS, a kody wyjątku blokującego – z kodem stanu EXCEPTIONS.

Przykład odpowiedzi z wyjątkiem znajduje się w tym fragmencie kodu:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "SUCCESS",
      "states": {
        "online": true,
        "isPaused": false,
        "isRunning": false,
        "exceptionCode": "runCycleFinished"
      }
    }]
  }
}

Asystent odpowiada:

„Pralka skończyła pracę”.

Aby dodać raportowanie błędów dla pralki, otwórz functions/index.js i dodaj definicję klasy błędów, jak pokazano w tym fragmencie kodu:

index.js

app.onQuery(async (body) => {...});

// Add SmartHome error handling
class SmartHomeError extends Error {
  constructor(errorCode, message) {
    super(message);
    this.name = this.constructor.name;
    this.errorCode = errorCode;
  }
}

Zaktualizuj odpowiedź na wykonanie, aby zwrócić kod błędu i stan błędu:

index.js

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) => {
          ...
        })
        //Add error response handling
        .catch((error) => {
          functions.logger.error('EXECUTE', device.id, error);
          result.ids.push(device.id);
          if (error instanceof SmartHomeError) {
            result.status = 'ERROR';
            result.errorCode = error.errorCode;
          }
        })
      );
    }
  }
}

Asystent może teraz poinformować użytkowników o dowolnym kodzie błędu, który został zgłoszony. W następnej sekcji znajdziesz konkretny przykład.

7. Dodawanie dodatkowej weryfikacji użytkownika

Jeśli Twoje urządzenie ma tryby, które wymagają zabezpieczenia lub powinny być ograniczone do określonej grupy autoryzowanych użytkowników, takich jak aktualizacja oprogramowania lub odblokowanie blokady, w ramach integracji należy wdrożyć dodatk weryfikujący użytkownika.

Możesz wdrożyć dodatkową weryfikację użytkownika na wszystkich typach i cechach urządzeń, dostosowując ustawienia tak, aby wyzwanie bezpieczeństwa było wyświetlane za każdym razem lub aby spełnianie określonych kryteriów było wymagane.

Obsługiwane typy wyzwań:

  • No challenge – żądanie i odpowiedź, które nie używają testu uwierzytelniania (jest to zachowanie domyślne)
  • ackNeeded – dodatkowa weryfikacja użytkownika, która wymaga wyraźnego potwierdzenia (tak lub nie).
  • pinNeeded – dodatkowa weryfikacja użytkownika, która wymaga podania osobistego numeru identyfikacyjnego (PIN)

W tym ćwiczeniu dodaj do polecenia włączania pralki wyzwanie ackNeeded, a także funkcję zwracającą błąd, jeśli nie uda się przeprowadzić weryfikacji dodatkowej.

Otwórz functions/index.js i dodaj definicję klasy błędów, która zwraca kod błędu i typ wyzwania, jak w tym fragmencie kodu:

index.js

class SmartHomeError extends Error { ... }

// Add secondary user verification error handling
class ChallengeNeededError extends SmartHomeError {
  /**
   * Create a new ChallengeNeededError
   * @param {string} suvType secondary user verification challenge type
   */
  constructor(suvType) {
    super('challengeNeeded', suvType);
    this.suvType = suvType;
  }
}

Musisz też zaktualizować odpowiedź na wykonanie, aby zwracać błąd challengeNeeded w ten sposób:

index.js

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) => {
          ...
        })
        .catch((error) => {
          functions.logger.error('EXECUTE', device.id, error);
          result.ids.push(device.id);
          if (error instanceof SmartHomeError) {
            result.status = 'ERROR';
            result.errorCode = error.errorCode;
            //Add error response handling
            if (error instanceof ChallengeNeededError) {
              result.challengeNeeded = {
                type: error.suvType
              };
            }
          }
        })
      );
    }
  }
}

Na koniec zmodyfikuj updateDevice, aby wymagać wyraźnego potwierdzenia włączenia lub wyłączenia pralki.

index.js

const updateDevice = async (execution,deviceId) => {
  const {challenge,params,command} = execution; //Add secondary user challenge
  let state, ref;
  switch (command) {
    case 'action.devices.commands.OnOff':
      //Add secondary user verification challenge
      if (!challenge || !challenge.ack) {
        throw new ChallengeNeededError('ackNeeded');
      }
      state = {on: params.on};
      ref = firebaseRef.child(deviceId).child('OnOff');
      break;
    ...
  }

  return ref.update(state)
      .then(() => state);
};

Wdrażanie w Firebase

Aby wdrożyć zaktualizowaną funkcję, uruchom to polecenie:

firebase deploy --only functions

Po wdrożeniu zaktualizowanego kodu musisz potwierdzić polecenie głosowo, gdy poprosisz Asystenta o włączenie lub wyłączenie pralki. Przykład:

Ty: „OK Google, włącz pralkę”

Asystent: „Czy na pewno chcesz włączyć pralkę?”

Ty: „Tak”.

Szczegółowe odpowiedzi na poszczególne etapy weryfikacji dodatkowej użytkownika możesz też sprawdzić, otwierając logi Firebase.

289dbe48f4bb8106.png

8. Gratulacje

674c4f4392e98c1.png

Gratulacje! Rozszerzyliśmy funkcje integracji między chmurami za pomocą atrybutów Modes i Toggles oraz zabezpieczyliśmy ich wykonywanie za pomocą dodatkowej weryfikacji użytkownika.

Więcej informacji

Oto kilka pomysłów, które możesz wdrożyć, aby uzyskać więcej informacji:

  • Dodaj na urządzeniach funkcje wykonania lokalnego.
  • Aby zmienić stan urządzenia, użyj innego typu weryfikacji dodatkowej użytkownika.
  • Zaktualizuj odpowiedź na zapytanie QUERY dotyczące cechy RunCycle, aby aktualizować ją dynamicznie.
  • Zapoznaj się z tym przykładem na GitHubie.