Ulepszaj i zabezpieczaj inteligentne działania domowe

1. Zanim zaczniesz

Akcje inteligentnego domu używają typów urządzeń, aby informować Asystenta Google o tym, jaka gramatyka ma być używana na urządzeniu. Cechy urządzenia określają możliwości danego typu urządzeń. Urządzenie dziedziczy stany każdej cechy urządzenia dodanej do akcji.

dc8dce0dea87cd5c.png

Możesz połączyć dowolne obsługiwane cechy z wybranym typem urządzenia, aby dostosować funkcje urządzeń użytkowników. Jeśli chcesz zaimplementować w akcjach cechy niestandardowe, które są obecnie niedostępne w schemacie urządzenia, cechy Tryby i Przełączniki umożliwiają kontrolowanie określonych ustawień za pomocą własnej, niestandardowej nazwy.

Oprócz podstawowych funkcji kontroli dostępnych w poszczególnych typach i cechach Smart Home API oferuje też dodatkowe funkcje, które zwiększają wygodę użytkowników. Odpowiedzi na błędy zapewniają szczegółowe informacje zwrotne użytkownika, jeśli intencje nie zakończą się powodzeniem. Dodatkowa weryfikacja użytkownika rozszerza te odpowiedzi i zwiększa bezpieczeństwo wybranej funkcji urządzenia. Wysyłając określone odpowiedzi o błędach do bloków testów uruchamianych przez Asystenta, akcja inteligentnego domu może wymagać dodatkowej autoryzacji do wykonania polecenia.

Wymagania wstępne

Co utworzysz

W ramach tego ćwiczenia w programie wdrożysz gotową integrację inteligentnego domu z Firebase, a następnie nauczysz się dodawać niestandardowe cechy do inteligentnej pralki domowej pod kątem rozmiaru obciążenia i trybu turbo. Zaimplementujesz też raportowanie błędów i wyjątków oraz nauczysz się wymuszać słowne potwierdzenie włączenia pralki za pomocą dodatkowej weryfikacji użytkownika.

Czego się nauczysz

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

Czego potrzebujesz

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, utwórz 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

  1. Otwórz Konsolę programisty Actions on Google.
  2. Kliknij 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

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

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.

ee198858a6eac112.png

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-traits.git

Rozpakuj pobrany plik ZIP.

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.

Podana realizacja w chmurze obejmuje te funkcje w projekcie index.js:

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

Łą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:

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

5845443e94705557.png

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

9d7b223427f587ca.png

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

774d0c40c351c7da.png

a8c4673eb11d76ee.png

Żeby włączyć łączenie kont, w menu nawigacyjnym po lewej stronie wybierz opcję Programowanie > Łączenie kont. Użyj tych ustawień łączenia kont:

Identyfikator klienta

ABC123

Tajny klucz klienta

DEF456

Adres URL autoryzacji

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

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 Symulatora. Jeśli nie widzisz opcji „Testuj teraz włączony”, 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. Umożliwi Ci to testowanie na platformach Asystenta Google i w aplikacji Google Home po zalogowaniu się na to samo konto.

  1. Na telefonie otwórz ustawienia Asystenta Google. Pamiętaj, aby zalogować się na to samo konto co w konsoli.
  2. Wybierz Asystent Google > Ustawienia > Sterowanie domem (w sekcji Asystent).
  3. Kliknij ikonę wyszukiwania w prawym górnym rogu.
  4. Wyszukaj swoją aplikację testową, korzystając z prefiksu [test].
  5. 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ę.

ae252220753726f6.png

Sprawdź, czy możesz sterować pralką za pomocą poleceń głosowych w aplikacji Google Home. Zmiana stanu urządzenia powinna też być widoczna w interfejsie internetowym frontendu w 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 ustawienie na urządzeniu dowolnej liczby ustawień trybu, z których można wybrać tylko jedno ustawienie naraz. Dodajesz tryb do prania, aby określić rozmiar prania: mały, średni lub duży.

Aktualizacja odpowiedzi SYNC

Musisz dodać informacje o nowej cechy do swojej odpowiedzi na pytanie SYNC w functions/index.js. Te dane są wyświetlane 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 pokazany poniżej.

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;
}

Zaktualizuj odpowiedź na zapytanie QUERY

Następnie zaktualizuj odpowiedź (QUERY), aby zgłosić bieżący stan pralki.

Dodaj zaktualizowane zmiany do funkcji queryFirebase i queryDevice, aby uzyskać stan 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,
    // 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,
    },
  };
};

Stan aktualizacji raportu

Na koniec zaktualizuj funkcję reportstate, aby przesyłać aktualne ustawienia pralki na wykres główny.

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 przejdź do interfejsu internetowego i kliknij przycisk Odśwież ae8d3b25777a5e30.png na pasku narzędzi. Spowoduje to uruchomienie synchronizacji żądań, dzięki czemu Asystent otrzyma zaktualizowane dane odpowiedzi w usłudze SYNC.

bf4f6a866160a982.png

Teraz podaj polecenie ustawienia trybu pralki, na przykład:

„OK Google, ustaw naładowanie pralki na duże”.

Możesz też zadać pytanie na temat pralki, na przykład:

„OK Google, jakie jest naładowanie pralki?”

5. Dodaj przełączniki

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

Aktualizacja odpowiedzi SYNC

W odpowiedzi SYNC musisz dodać informacje o nowej cechy urządzenia. Pojawi się on w tablicy traits i obiekcie attributes, tak jak 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ń intencji EXECUTE

W intencji EXECUTE dodaj polecenie action.devices.commands.SetToggles w sposób pokazany poniżej.

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;
  }

Zaktualizuj odpowiedź na zapytanie QUERY

Na koniec musisz zaktualizować odpowiedź (QUERY), żeby zgłosić tryb turbo. 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,
    },
  };
};

Stan aktualizacji raportu

Na koniec zaktualizuj funkcję reportstate, aby raportowała Home Graph, czy pralka działa w trybie 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 wdrożenia uruchomić żądanie synchronizacji.

Teraz możesz wydawać polecenie włączenia trybu turbo:

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

Możesz też sprawdzić, czy pralka działa już w trybie turbo:

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

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

Obsługa błędów w akcji inteligentnego domu umożliwia zgłaszanie użytkownikom problemów, które powodują niepowodzenia odpowiedzi EXECUTE i QUERY. Powiadomienia zapewniają użytkownikom lepsze wrażenia, gdy korzystają 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 chcesz na przykład zgłosić błąd przy próbie uruchomienia pralki 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 jeszcze raz”.

Wyjątki są podobne do błędów, ale wskazują, kiedy z poleceniem powiązany jest alert, który może (ale nie musi) zablokować pomyślne wykonanie polecenia. Wyjątek może obejmować powiązane informacje z użyciem cechy StatusReport, takie jak poziom naładowania baterii lub ostatnia zmiana stanu. Kody nieblokujących wyjątków są zwracane ze stanem SUCCESS, a kody wyjątków blokujących 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"
      }
    }]
  }
}

Asystent odpowiada:

„Pralka zakończyła pracę”.

Aby dodać raportowanie błędów pralki, otwórz functions/index.js i dodaj definicję klasy błędu podaną 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ź o wykonaniu, 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;
            }
          })
      );
    }
  }
}

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

7. Dodawanie dodatkowej weryfikacji użytkownika

Zaimplementuj w akcji dodatkową weryfikację użytkownika, jeśli urządzenie ma tryby, które muszą być zabezpieczone lub powinny być ograniczone do określonej grupy autoryzowanych użytkowników (np. aktualizacja oprogramowania lub blokada).

Możesz wdrożyć dodatkową weryfikację użytkownika na wszystkich typach urządzeń i cechach, aby określić, czy test zabezpieczający ma miejsce za każdym razem, czy musi zostać spełniony konkretne kryteria.

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

  • No challenge – żądanie i odpowiedź bez testu zabezpieczającego uwierzytelnianie (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 ramach tego ćwiczenia w programowaniu dodaj do polecenia ackNeeded test zabezpieczający logowanie i funkcję zwracania błędu, gdy druga próba weryfikacji się nie powiedzie.

Otwórz functions/index.js i dodaj definicję klasy błędu, która zwraca kod błędu i typ wyzwania, 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, aby 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 zmodyfikuj updateDevice tak, aby podczas włączania lub wyłączania pralki wymagało wyraźnego potwierdzenia.

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:

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

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

Ty: „Tak”.

Możesz też zobaczyć szczegółową odpowiedź na każdy krok dodatkowej weryfikacji użytkownika w dziennikach Firebase.

289dbe48f4bb8106.png

8. Gratulacje

674c4f4392e98c1.png

Gratulacje! Rozszerzyliśmy funkcje akcji w inteligentnym domu o cechy Modes i Toggles oraz zadbasz o ich wykonanie dzięki dodatkowej weryfikacji użytkowników.

Więcej informacji

Oto kilka pomysłów, które możesz wykorzystać, aby zwiększyć swoją skuteczność:

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