Ulepszaj i zabezpieczaj inteligentne działania domowe

1. Zanim zaczniesz

Akcje w inteligentnym domu korzystają z typów urządzeń, żeby przekazać Asystentowi Google informację, jakiej gramatyki należy użyć na urządzeniu. Charakterystyka urządzenia określają możliwości danego typu urządzenia. Urządzenie dziedziczy stany każdej cechy urządzenia dodanej do akcji.

dc8dce0dea87cd5c.png

Do wybranego typu urządzenia możesz połączyć dowolne obsługiwane cechy, aby dostosować funkcje użytkowników urządzenia. Jeśli w działaniach chcesz wdrożyć niestandardowe cechy, które są obecnie niedostępne w schemacie urządzenia, możesz zastosować cechy Tryby i Przełączniki. kontrolkę z niestandardową nazwą.

Oprócz podstawowych funkcji sterowania zapewnianych przez typy i cechy, Smart Home API ma dodatkowe funkcje, które zwiększają wygodę użytkowników. Odpowiedzi na błędy zawierają szczegółowe opinie użytkowników, gdy intencje nie powiodły się. Dodatkowa weryfikacja użytkownika rozszerza te odpowiedzi i zwiększa bezpieczeństwo wybranej cechy urządzenia. Wysyłając określone odpowiedzi na błędy w blokadach testów wysyłanych przez Asystenta, działanie inteligentnego domu może wymagać dodatkowej autoryzacji przed ukończeniem polecenia.

Wymagania wstępne

Co utworzysz

W ramach tego ćwiczenia w programie wdrożysz gotową integrację inteligentnego domu z Firebase. Następnie dowiesz się, jak dodać niestandardowe cechy do inteligentnej pralki, aby dostosować rozmiar załadunku i tryb turbo. Wdrożysz też raportowanie błędów i wyjątków i nauczysz się, jak wymusić słowne potwierdzanie w celu włączenia pralki za pomocą dodatkowej weryfikacji użytkownika.

Czego się nauczysz

  • Jak dodać tryby i przełączać cechy do akcji
  • Zgłaszanie błędów i wyjątków
  • Jak zastosować dodatkową weryfikację użytkownika

Czego potrzebujesz

2. Pierwsze kroki

Włączanie Zarządzania aktywnością

Aby korzystać z Asystenta Google, musisz udostępniać Google określone dane dotyczące aktywności. Asystent Google potrzebuje tych danych do prawidłowego działania. jednak wymóg udostępniania danych nie dotyczy tylko pakietu SDK. Aby udostępnić 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ą dla konta Google, którego chcesz używać z Asystentem.

Upewnij się, że te przełączniki są włączone:

  • Internet i Aktywność w 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
  • Głos Aktywność związana z dźwiękiem

Tworzenie projektu w Actions

  1. Otwórz konsolę programisty Actions on Google.
  2. Kliknij New Project (Nowy projekt), wpisz nazwę projektu i kliknij UTWÓRZ PROJEKT.

3d6b68ca79afd54c.png

Wybierz aplikację Inteligentny dom.

Na ekranie Przegląd w Konsoli Actions wybierz Inteligentny dom.

2fa4988f44f8914b.png

Wybierz kartę Inteligentny dom i kliknij Rozpocznij tworzenie. Przekierujemy Cię do konsoli projektu.

Instalowanie interfejsu wiersza poleceń Firebase

Interfejs wiersza poleceń Firebase (CLI) pozwala udostępniać aplikacje internetowe lokalnie i wdrażać je 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

Włączanie interfejsu HomeGraph API

Interfejs HomeGraph API umożliwia przechowywanie urządzeń i tworzenie o nich zapytań oraz wysyłanie do nich zapytań w obrębie 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 pasuje do działań.<project-id>.Następnie na ekranie „API Library” (Biblioteka API) interfejsu HomeGraph API kliknij Włącz.

ee198858a6eac112.png

3. Uruchom aplikację startową

Po skonfigurowaniu środowiska programistycznego możesz wdrożyć projekt startowy, aby sprawdzić, czy wszystko jest prawidłowo skonfigurowane.

Pobieranie kodu źródłowego

Kliknij ten link, aby pobrać na swoim komputerze przykładową wersję ćwiczenia z programowania:

...lub sklonuj repozytorium GitHub, używając wiersza poleceń:

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

Rozpakuj pobrany plik ZIP.

Informacje o projekcie

Projekt startowy zawiera te podkatalogi:

  • public: Interfejs frontendu do łatwego kontrolowania i monitorowania stanu inteligentnej pralki.
  • functions: W pełni wdrożona usługa w chmurze, która zarządza inteligentną pralką za pomocą Cloud Functions dla Firebase i Bazy danych czasu rzeczywistego Firebase.

Udostępniona realizacja w chmurze obejmuje w index.js te funkcje:

  • fakeauth: punkt końcowy autoryzacji na potrzeby łączenia kont
  • faketoken: punkt końcowy tokena służący do łączenia kont
  • smarthome: punkt końcowy realizacji intencji inteligentnego domu
  • reportstate: wywołuje interfejs Home Graph API przy zmianach stanu urządzenia
  • requestsync: umożliwia aktualizacje urządzeń użytkownika bez konieczności ponownego łączenia kont

Połącz z Firebase

Przejdź do katalogu washer-start, a potem skonfiguruj interfejs wiersza poleceń Firebase za pomocą projektu Actions:

cd washer-start
firebase use <project-id>

Skonfiguruj projekt Firebase

Zainicjuj projekt Firebase.

firebase init

Wybierz funkcje interfejsu wiersza poleceń, Bazę 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 interfejsów API i funkcji niezbędnych dla Twojego projektu.

Gdy pojawi się prośba, 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 startowego projektu, wybierz domyślny plik dla 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, wybierz Zastąp, gdy pojawi się pytanie, czy chcesz zainicjować czy zastąpić bazę kodu.

? Would you like to initialize a new codebase, or overwrite an existing one?
Overwrite

Podczas konfigurowania funkcji należy użyć plików domyślnych i nie zastąpić istniejących plików index.js i 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, 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żyć katalogu public w kodzie projektu i użyć istniejącego pliku index.html. Gdy pojawi się pytanie o użycie 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ł przypadkowo włączony, można go wyłączyć na 2 sposoby:

  1. Korzystając z GUI, przejdź do folderu ../functions w projekcie, wybierz ukryty plik .eslintrc.js i usuń go. Nie pomyl go z podobną nazwą (.eslintrc.json).
  2. Przy użyciu wiersza 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

Oto dane wyjściowe konsoli, które powinny Ci się wyświetlić:

...

✔ 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 URL hostingu w przeglądarce (https://<project-id>.web.app), aby wyświetlić aplikację internetową. Zobaczysz następujący interfejs:

5845443e94705557.png

Ten interfejs internetowy reprezentuje platformę innej firmy do wyświetlania lub modyfikowania stanów urządzeń. Aby rozpocząć wypełnianie bazy danych informacjami z urządzenia, kliknij AKTUALIZUJ. Na stronie nie pojawią się żadne zmiany, ale w bazie danych zostanie zapisany bieżący stan pralki.

Pora połączyć wdrożoną przez Ciebie usługę w chmurze z Asystentem Google za pomocą konsoli Actions.

Konfigurowanie projektu w konsoli Actions

W sekcji Przegląd > Utwórz akcję, kliknij Dodaj działania. Wpisz adres URL funkcji w Cloud Functions, która umożliwia realizację intencji inteligentnego domu, i kliknij Zapisz.

https://us-central1-<project-id>.cloudfunctions.net/smarthome

9d7b223427f587ca.png

W menu Programowanie > Na karcie Wywołanie dodaj wyświetlaną nazwę akcji i kliknij Zapisz. Ta nazwa będzie widoczna w aplikacji Google Home.

774d0c40c351c7da.png

a8c4673eb11d76ee.png

Aby włączyć łączenie kont, kliknij menu Programowanie > Łączenie kont w panelu nawigacyjnym po lewej stronie. Użyj tych ustawień łączenia kont:

Identyfikator klienta

ABC123

Tajny klucz klienta

DEF456

Adres URL autoryzacji

https://us-central1-<project-id>.cloudfunctions.net/fakeauth

Adres URL tokena

https://us-central1-<project-id>.cloudfunctions.net/faketoken

9730d20b90bcc038.png

Kliknij Zapisz, aby zapisać konfigurację łączenia kont, a potem kliknij Przetestuj, aby włączyć testowanie w projekcie.

ee0547f05b5efd98.png

Przekierujemy Cię do aplikacji Simulator. Jeśli nie widzisz opcji „Przetestuj teraz”, kliknij Resetuj test, aby sprawdzić, czy testowanie jest włączone.

d0495810dbadf059.png

Aby przetestować działanie inteligentnego domu, musisz połączyć swój projekt z kontem Google. Dzięki temu możesz przeprowadzać testy za pomocą Asystenta Google i aplikacji Google Home, na których zalogujesz się na to samo konto.

  1. Na telefonie otwórz ustawienia Asystenta Google. Pamiętaj, że musisz zalogować się na to samo konto co w konsoli.
  2. Kliknij Asystent Google > Ustawienia > Sterowanie domem (w sekcji Asystent).
  3. W prawym górnym rogu kliknij ikonę wyszukiwania.
  4. Aby znaleźć swoją aplikację testową, wyszukaj ją, używając prefiksu [test].
  5. Wybierz ten element. Asystent Google uwierzytelni się w usłudze i wyśle żądanie SYNC, prosząc usługę o udostępnienie listy urządzeń użytkownika.

Otwórz aplikację Google Home i sprawdź, czy widzisz pralkę.

ae252220753726f6.png

Sprawdź, czy możesz sterować pralką, używając poleceń głosowych w aplikacji Google Home. Zmiana stanu urządzenia powinna być też widoczna w interfejsie internetowym frontendu realizacji w chmurze.

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

4. Dodaj środki transportu

Cecha action.devices.traits.Modes umożliwia urządzeniu ustawienie dowolnej liczby ustawień trybu, z których w danym momencie można ustawić tylko 1 z nich. Dodasz tryb pralki, aby określić rozmiar wczytywanego prania: mały, średni lub duży.

Zaktualizuj odpowiedź SYNC

Musisz dodać informacje o nowej cechy do odpowiedzi SYNC w zadaniu functions/index.js. Te dane są widoczne 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,
          }],
        },
      }],
    },
  };
});

Dodaj nowe polecenia intencji EXECUTE

W intencji EXECUTE dodaj polecenie action.devices.commands.SetModes w sposób przedstawiony w poniższym 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 QUERY

Następnie zaktualizuj odpowiedź QUERY, aby informować o bieżącym stanie pralki.

Dodaj zaktualizowane zmiany do funkcji queryFirebase i queryDevice, aby uzyskać stan przechowywany w bazie danych czasu rzeczywistego.

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ła aktualne ustawienie obciążenia pralki na wykres domowy.

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

Uruchom to polecenie, aby wdrożyć zaktualizowane działanie:

firebase deploy --only functions

Po zakończeniu wdrażania otwórz interfejs internetowy i kliknij przycisk Odśwież ae8d3b25777a5e30.png na pasku narzędzi. Powoduje to synchronizację żądań, dzięki czemu Asystent otrzymuje zaktualizowane dane odpowiedzi SYNC.

bf4f6a866160a982.png

Teraz możesz wydać polecenie ustawiania trybu pralki, na przykład:

„OK Google, ustaw duży poziom załadunku pralki”.

Możesz też zadać pytania na temat pralki, np.:

„OK Google, jaka jest pojemność pralki?”

5. Dodaj przełączniki

Cecha action.devices.traits.Toggles reprezentuje nazwane aspekty urządzenia, które mają stan prawda lub fałsz, na przykład czy pralka jest w trybie turbo.

Zaktualizuj odpowiedź SYNC

W odpowiedzi na pytanie SYNC musisz podać informacje o nowej trai urządzenia. Pojawi się on w tablicy traits i obiekcie attributes, jak pokazano poniżej.

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',
            }],
          }],
        },
      }],
    },
  };
});

Dodaj nowe polecenia intencji EXECUTE

W intencji EXECUTE dodaj polecenie action.devices.commands.SetToggles w sposób przedstawiony w poniższym 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 QUERY

Na koniec musisz zaktualizować odpowiedź funkcji QUERY, aby zgłosić tryb turbo pralki. Dodaj zaktualizowane zmiany do funkcji queryFirebase i queryDevice, aby uzyskać stan przełączania zapisany w bazie danych czasu rzeczywistego.

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 przesyłała do Home Graph, czy pralka jest ustawiona na 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

Uruchom to polecenie, aby wdrożyć zaktualizowane funkcje:

firebase deploy --only functions

Kliknij przycisk Odśwież ae8d3b25777a5e30.png w interfejsie internetowym, aby po zakończeniu wdrażania aktywować synchronizację żądań.

Teraz możesz wydać polecenie przełączenia pralki w tryb turbo, mówiąc:

„OK Google, włącz turbo pralki”.

Możesz też sprawdzić, czy pralka działa już w trybie turbo, mówiąc:

„OK Google, czy pralka działa w trybie turbo?”

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

Obsługa błędów w działaniu inteligentnego domu umożliwia zgłaszanie użytkownikom, gdy problemy powodują błędy EXECUTE i QUERY. Powiadomienia zwiększają wygodę użytkowników korzystających z Twojego urządzenia i akcji.

Za każdym razem, gdy żądanie EXECUTE lub QUERY nie powiedzie się, akcja powinna zwrócić kod błędu. Jeśli na przykład chcesz zgłosić błąd, gdy użytkownik pró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, mówiąc:

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

Wyjątki są podobne do błędów, ale wskazują, kiedy polecenie jest powiązane z alertem, co może, ale nie musi, blokować wykonanie polecenia. Wyjątkiem mogą być powiązane informacje za pomocą cechy StatusReport, takie jak poziom baterii czy ostatnia zmiana stanu. Nieblokujące kody wyjątków są zwracane razem ze stanem SUCCESS, a blokujące kody wyjątków są zwracane ze stanem EXCEPTIONS.

Przykładowa odpowiedź 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"
      }
    }]
  }
}

W odpowiedzi Asystent mówi:

„Pralka przestała działać”.

Aby dodać raportowanie błędów dotyczących pralki, otwórz aplikację functions/index.js i dodaj definicję klasy błędu zgodnie z tym fragmentem 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ź wykonania, aby zwracała 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( ... )
          //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;
            }
          })
      );
    }
  }
}

Teraz Asystent może informować użytkowników o każdym zgłoszonym przez Ciebie kodzie błędu. W następnej sekcji zobaczysz konkretny przykład.

7. Dodawanie dodatkowej weryfikacji użytkownika

Jeśli działanie urządzenia ma tryb, który wymaga zabezpieczenia lub powinno być ograniczone do określonej grupy autoryzowanych użytkowników, np. aktualizacja oprogramowania lub wyłączenie blokady, zastosuj w akcji dodatkową weryfikację użytkownika.

Dodatkową weryfikację użytkownika możesz wdrożyć na wszystkich typach urządzeń i wszystkich cechach, określając, czy test zabezpieczający ma miejsce za każdym razem, czy trzeba spełnić określone kryteria.

Dostępne są trzy obsługiwane typy wyzwań:

  • No challenge – żądanie i odpowiedź bez testu zabezpieczającego uwierzytelnienie (jest to działanie domyślne).
  • ackNeeded – dodatkowa weryfikacja użytkownika wymagająca jednoznacznego potwierdzenia (tak lub nie).
  • pinNeeded – dodatkowa weryfikacja użytkownika, która wymaga podania osobistego numeru identyfikacyjnego (PIN).

Na potrzeby tego ćwiczenia w programie dodaj wyzwanie ackNeeded do polecenia włączania pralki oraz funkcję zwracania błędu, jeśli druga weryfikacja się nie powiedzie.

Otwórz functions/index.js i dodaj definicję klasy błędu, która zwraca kod błędu i typ testu zabezpieczającego, tak 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ź wykonania, by zwracała 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( ... )
          .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 zmień ustawienie 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

Uruchom to polecenie, aby wdrożyć zaktualizowaną funkcję:

firebase deploy --only functions

Po wdrożeniu zaktualizowanego kodu musisz ustnie potwierdzić, że prosisz Asystenta o włączenie lub wyłączenie pralki. Przykładowe działania:

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

Asystent: „Na pewno chcesz włączyć pralkę?”.

Ty: „Tak”.

Możesz też zobaczyć szczegółową odpowiedź dotyczącą każdego kroku dodatkowej weryfikacji użytkownika w dziennikach Firebase.

289dbe48f4bb8106.png

8. Gratulacje

674c4f4392e98c1.png

Gratulacje! Rozszerzyłeś funkcje inteligentnego domu o cechy Modes i Toggles oraz zabezpieczyłeś(-aś) ich wykonanie dzięki dodatkowej weryfikacji użytkownika.

Więcej informacji

Oto kilka pomysłów, które możesz zastosować, aby zgłębić temat:

  • Dodaj na urządzeniach możliwość lokalnego wykonywania.
  • Aby zmienić stan urządzenia, użyj innego typu dodatkowej weryfikacji użytkownika.
  • Zaktualizuj odpowiedź QUERY funkcji RunCycle, aby aktualizować się dynamicznie.
  • Zapoznaj się z tym przykładem na GitHubie.