Debugowanie lokalnego domu

1. Zanim zaczniesz

Integracje inteligentnego domu umożliwiają Asystentowi Google sterowanie połączonymi urządzeniami w domach użytkowników. Aby utworzyć integrację typu chmura-chmura, musisz podać punkt końcowy webhooka w chmurze, który będzie obsługiwać intencje inteligentnego domu. Gdy na przykład użytkownik powie „OK Google, włącz światła”, Asystent wyśle polecenie do Twojej usługi w chmurze, aby zaktualizować stan urządzenia.

Pakiet Local Home SDK ulepsza integrację inteligentnego domu, dodając lokalną ścieżkę do kierowania intencji inteligentnego domu bezpośrednio do urządzenia Google Home. Zwiększa to niezawodność i zmniejsza opóźnienie w przetwarzaniu poleceń użytkowników. Umożliwia on pisanie i wdrażanie aplikacji do lokalnej realizacji w języku TypeScript lub JavaScript, która identyfikuje urządzenia i wykonuje polecenia na dowolnym głośniku inteligentnym Google Home lub inteligentnym ekranie Google Nest. Aplikacja komunikuje się bezpośrednio z istniejącymi urządzeniami inteligentnymi użytkowników w lokalnej sieci komputerowej, używając standardowych protokołów do realizacji poleceń.

72ffb320986092c.png

Debugowanie integracji typu chmura-chmura jest kluczowym krokiem w tworzeniu integracji o jakości produkcyjnej, ale bez informacyjnych i łatwych w użyciu narzędzi do rozwiązywania problemów i testowania jest to trudne i czasochłonne. Aby ułatwić debugowanie integracji typu chmura-chmura, dostępne są wskaźniki Google Cloud Platform (GCP) Metrics i Logging oraz pakiet Test Suite for inteligentny dom, które pomagają identyfikować i rozwiązywać problemy z integracjami.

Wymagania wstępne

Co utworzysz

W tym ćwiczeniu z programowania utworzysz lokalną realizację w przypadku integracji typu chmura-chmura i połączysz ją z Asystentem. Następnie przeprowadzisz debugowanie aplikacji Local Home za pomocą zestawu testów dla inteligentnego domu oraz wskaźników i logowania Google Cloud Platform (GCP).

Czego się nauczysz

  • Jak używać wskaźników i logowania GCP do identyfikowania i rozwiązywania problemów w środowisku produkcyjnym.
  • Jak używać pakietu Test Suite do identyfikowania problemów z funkcjami i interfejsem API.
  • Jak używać Narzędzi deweloperskich w wersji deweloperskiej Chrome podczas tworzenia aplikacji Home.

Czego potrzebujesz

  • Najnowsza wersja Google Chrome
  • Urządzenie z iOS lub Androidem z aplikacją Google Home
  • Głośnik inteligentny Google Home lub inteligentny ekran Google Nest
  • Node.js w wersji 24 lub nowszej
  • konto Google,
  • konto rozliczeniowe Google Cloud

2. Uruchamianie aplikacji pralki

Pobieranie kodu źródłowego

Kliknij ten link, aby pobrać na komputer używany do programowania przykładowy kod do tego ćwiczenia:

Możesz też sklonować repozytorium GitHub z wiersza poleceń:

$ git clone https://github.com/google-home/smarthome-debug-local.git

Informacje o projekcie

Aplikacja startowa zawiera podobne podkatalogi i funkcje w Cloud Functions jak w ćwiczeniu Włączanie lokalnej realizacji w przypadku integracji typu chmura-chmura. Zamiast app-start mamy tu jednak app-faulty. Zaczniemy od aplikacji Local Home, która działa, ale nie najlepiej.

Łączenie Analytics z Firebase

Będziemy używać tego samego projektu, który został utworzony w Włączanie lokalnej realizacji w przypadku integracji typu chmura-chmura ćwiczeniu z programowania, ale wdrożymy pliki pobrane w tym ćwiczeniu.

Otwórz katalog app-faulty, a następnie skonfiguruj wiersz poleceń Firebase za pomocą projektu integracji utworzonego w ćwiczeniu z programowania Włączanie lokalnej realizacji w przypadku integracji typu chmura-chmura:

$ cd app-faulty
$ firebase use <project-id>

Wdrażanie w Firebase

Otwórz folder app-faulty/functions i zainstaluj wszystkie niezbędne zależności za pomocą npm:

$ cd functions
$ npm install

Uwaga: jeśli zobaczysz ten komunikat, możesz go zignorować i kontynuować. Ostrzeżenie jest spowodowane starszymi zależnościami. Więcej informacji znajdziesz tutaj.

found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details

Otwórz katalog app-faulty/local/ i uruchom te polecenia, aby pobrać kompilator TypeScript i skompilować aplikację:

$ cd ../local
$ npm install
$ npm run build

Spowoduje to skompilowanie źródła index.ts (TypeScript) i umieszczenie tych treści w katalogu app-faulty/public/local-home/:

  • bundle.js – skompilowany kod JavaScript zawierający aplikację lokalną i zależności.
  • index.html – strona hostingu lokalnego używana do udostępniania aplikacji na potrzeby testowania na urządzeniu.

Po zainstalowaniu zależności i skonfigurowaniu projektu możesz po raz pierwszy uruchomić aplikację.

$ firebase deploy

Oto dane wyjściowe, które powinny się pojawić w konsoli:

...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/<project-id>/overview
Hosting URL: https://<projectcd -id>.web.app

To polecenie wdraża aplikację internetową wraz z kilkoma funkcjami w Cloud Functions dla Firebase.

Aktualizowanie HomeGraph

Aby wyświetlić aplikację internetową, otwórz w przeglądarce adres URL hostingu (https://<project-id>.web.app). W interfejsie internetowym kliknij przycisk Odświeżae8d3b25777a5e30.png, aby zaktualizować HomeGraph za pomocą najnowszych metadanych urządzenia z wadliwej aplikacji pralki za pomocą funkcji Request Sync.

fa3c47f293cfe0b7.png

Otwórz aplikację Google Home i sprawdź, czy widzisz urządzenie pralki z nową nazwą „Faulty Washer”. Pamiętaj, aby przypisać urządzenie do pomieszczenia, w którym znajduje się urządzenie Nest.

2a082ee11d47ad1a.png

3. Uruchamianie inteligentnej pralki

Jeśli masz za sobą ćwiczenie z programowania Włączanie lokalnej realizacji w przypadku integracji typu chmura-chmura, wirtualna inteligentna pralka powinna być już uruchomiona. Jeśli jest zatrzymana, pamiętaj, aby ponownie uruchomić urządzenie wirtualne.

Uruchamianie urządzenia

Otwórz katalog virtual-device/ i uruchom skrypt urządzenia, przekazując parametry konfiguracji jako argumenty:

$ cd ../../virtual-device
$ npm install
$ npm start -- \
  --deviceId=deviceid123 --projectId=<project-id> \
  --discoveryPortOut=3311 --discoveryPacket=HelloLocalHomeSDK

Sprawdź, czy skrypt urządzenia działa z oczekiwanymi parametrami:

(...): UDP Server listening on 3311
(...): Device listening on port 3388
(...): Report State successful

4. Testowanie aplikacji Local Home

Wysyłaj polecenia do urządzenia za pomocą poleceń głosowych do urządzenia Google Home, np.:

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

„OK Google, uruchom pralkę”.

„OK Google, wymuś lokalne”.

„OK Google, zatrzymaj pralkę”.

Gdy po poleceniu „wymuś lokalne” spróbujesz sterować pralką, Asystent Google odpowie „Przepraszam, ale pralka jest teraz niedostępna”.

Oznacza to, że urządzenie jest niedostępne przez ścieżkę lokalną. Przed wydaniem polecenia „OK Google, wymuś lokalne” wszystko działało, ponieważ gdy urządzenie jest niedostępne przez ścieżkę lokalną, wracamy do ścieżki w chmurze. Po poleceniu „wymuś lokalne” opcja powrotu do ścieżki w chmurze jest jednak wyłączona.

Aby dowiedzieć się, na czym polega problem, skorzystajmy z dostępnych narzędzi: wskaźników Google Cloud Platform (GCP) Metrics i Logging oraz Narzędzi deweloperskich w Chrome.

5. Debugowanie aplikacji Local Home

W tej sekcji dowiesz się, dlaczego urządzenie jest niedostępne przez ścieżkę lokalną, korzystając z narzędzi udostępnianych przez Google. Za pomocą Narzędzi deweloperskich w Chrome możesz połączyć się z urządzeniem Google Home, wyświetlić logi konsoli i debugować aplikację Local Home. Możesz też wysyłać niestandardowe logi do Cloud Logging, aby wiedzieć, jakie błędy najczęściej występują w aplikacji Local Home.

Łączenie Narzędzi deweloperskich w Chrome

Aby połączyć debuger z aplikacją Local Home, wykonaj te czynności:

  1. Upewnij się, że urządzenie Google Home jest połączone z użytkownikiem, który ma uprawnienia dostępu do projektu w Konsoli dewelopera.
  2. Uruchom ponownie urządzenie Google Home, aby mogło pobrać adres URL HTML oraz konfigurację skanowania, którą umieścisz w Konsoli dewelopera.
  3. Uruchom Chrome na komputerze używanym do programowania.
  4. Otwórz nową kartę Chrome i w polu adresu wpisz chrome://inspect, aby uruchomić inspektora.

Na stronie powinna się wyświetlić lista urządzeń, a pod nazwą urządzenia Google Home powinien się pojawić adres URL aplikacji.

567f97789a7d8846.png

Uruchamianie inspektora

Aby uruchomić Narzędzia deweloperskie w Chrome, kliknij Zbadaj pod adresem URL aplikacji. Otwórz kartę Konsola i sprawdź, czy widzisz treść intencji IDENTIFY wydrukowaną przez aplikację TypeScript.

774c460c59f9f84a.png

Te dane wyjściowe oznaczają, że procedura obsługi IDENTIFY została wywołana, ale verificationId zwrócony w IdentifyResponse nie pasuje do żadnego z urządzeń w HomeGraph. Aby dowiedzieć się, dlaczego tak się dzieje, dodajmy kilka niestandardowych logów.

Dodawanie niestandardowych logów

Chociaż pakiet Local Home SDK drukuje błąd DEVICE_VERIFICATION_FAILED, nie pomaga on w znalezieniu głównej przyczyny. Dodajmy kilka niestandardowych logów, aby mieć pewność, że prawidłowo odczytujemy i przetwarzamy dane skanowania. Pamiętaj, że jeśli odrzucimy obietnicę z błędem, komunikat o błędzie zostanie też wysłany do Cloud Logging.

local/index.ts

identifyHandler(request: IntentFlow.IdentifyRequest):
    Promise<IntentFlow.IdentifyResponse> {
  console.log("IDENTIFY intent: " + JSON.stringify(request, null, 2));

  const scanData = request.inputs[0].payload.device.udpScanData;
  if (!scanData) {
    const err = new IntentFlow.HandlerError(request.requestId,
        'invalid_request', 'Invalid scan data');
    return Promise.reject(err);
  }

  // In this codelab, the scan data contains only local device id.
  // Is there something wrong here?
  const localDeviceId = Buffer.from(scanData.data);
  console.log(`IDENTIFY handler: received local device id
      ${localDeviceId}`);

  // Add custom logs
  if (!localDeviceId.toString().match(/^deviceid[0-9]{3}$/gi)) {
    const err = new IntentFlow.HandlerError(request.requestId,
        'invalid_device', 'Invalid device id from scan data ' +
        localDeviceId);
    return Promise.reject(err);
  }

  const response: IntentFlow.IdentifyResponse = {
    intent: Intents.IDENTIFY,
    requestId: request.requestId,
    payload: {
      device: {
        id: 'washer',
        verificationId: localDeviceId.toString(),
      }
    }
  };
  console.log("IDENTIFY response: " + JSON.stringify(response, null, 2));

  return Promise.resolve(response);
}

Zmień też wersję aplikacji Local Home, abyśmy mogli sprawdzić, czy używamy prawidłowej wersji.

local/index.ts

const localHomeSdk = new App('1.0.1');

Po dodaniu niestandardowych logów musisz ponownie skompilować aplikację i wdrożyć ją w Firebase.

$ cd ../app-faulty/local
$ npm run build
$ firebase deploy --only hosting

Teraz uruchom ponownie urządzenie Google Home, aby mogło wczytać zaktualizowaną aplikację Local Home. Możesz sprawdzić, czy urządzenie Google Home używa oczekiwanej wersji, sprawdzając logi Konsoli w Narzędziach deweloperskich w Chrome.

ecc56508ebcf9ab.png

Uzyskiwanie dostępu do Cloud Logging

Zobaczmy, jak używać Cloud Logging do znajdowania błędów. Aby uzyskać dostęp do Cloud Logging w swoim projekcie:

  1. W konsoli Cloud Platform otwórz stronę Projekty.
  2. Wybierz projekt inteligentnego domu.
  3. W sekcji Operacje wybierz Logowanie > Eksplorator logów.

Dostęp do danych logowania jest zarządzany za pomocą usługi Identity and Access Management (IAM) dla użytkowników projektu integracji. Więcej informacji o rolach i uprawnieniach dotyczących danych logowania znajdziesz w artykule Cloud Logging Kontrola dostępu.

Używanie filtrów zaawansowanych

Wiemy, że błędy występują w intencji IDENTIFY, ponieważ ścieżka lokalna nie działa, ponieważ nie można zidentyfikować urządzenia lokalnego. Chcemy jednak dokładnie wiedzieć, na czym polega problem, więc najpierw odfiltrujmy błędy występujące w procedurze obsługi IDENTIFY.

Kliknij przełącznik Pokaż zapytanie. Powinien się on zmienić w pole Konstruktor zapytań. W polu Konstruktor zapytań wpisz jsonPayload.intent="IDENTIFY" i kliknij przycisk Uruchom zapytanie.

4c0b9d2828ee2447.png

W rezultacie otrzymasz wszystkie logi błędów, które są zgłaszane w procedurze obsługi IDENTIFY. Następnie rozwiń ostatni błąd. Znajdziesz errorCode i debugString, które zostały ustawione podczas odrzucania obietnicy w procedurze obsługi IDENTIFY.

71f2f156c6887496.png

Z debugString możemy stwierdzić, że identyfikator urządzenia lokalnego ma nieprawidłowy format. Aplikacja Home oczekuje, że identyfikator urządzenia lokalnego będzie ciągiem znaków zaczynającym się od deviceid, po którym następują 3 cyfry, ale identyfikator urządzenia lokalnego jest tu ciągiem szesnastkowym.

Naprawianie błędu

Wracając do kodu źródłowego, w którym analizujemy identyfikator urządzenia lokalnego z danych skanowania, zauważamy, że podczas konwertowania ciągu znaków na bajty nie podaliśmy kodowania. Dane skanowania są odbierane jako ciąg szesnastkowy, więc podczas wywoływania Buffer.from() przekaż hex jako kodowanie znaków.

local/index.ts

identifyHandler(request: IntentFlow.IdentifyRequest):
    Promise<IntentFlow.IdentifyResponse> {
  console.log("IDENTIFY intent: " + JSON.stringify(request, null, 2));

  const scanData = request.inputs[0].payload.device.udpScanData;
  if (!scanData) {
    const err = new IntentFlow.HandlerError(request.requestId,
        'invalid_request', 'Invalid scan data');
    return Promise.reject(err);
  }

  // In this codelab, the scan data contains only local device id.
  const localDeviceId = Buffer.from(scanData.data, 'hex');
  console.log(`IDENTIFY handler: received local device id
      ${localDeviceId}`);

  if (!localDeviceId.toString().match(/^deviceid[0-9]{3}$/gi)) {
    const err = new IntentFlow.HandlerError(request.requestId,
      'invalid_device', 'Invalid device id from scan data ' +
      localDeviceId);
    return Promise.reject(err);
  }

  const response: IntentFlow.IdentifyResponse = {
    intent: Intents.IDENTIFY,
    requestId: request.requestId,
    payload: {
      device: {
        id: 'washer',
        verificationId: localDeviceId.toString(),
      }
    }
  };
  console.log("IDENTIFY response: " + JSON.stringify(response, null, 2));

  return Promise.resolve(response);
}

Zmień też wersję aplikacji Local Home, abyśmy mogli sprawdzić, czy używamy prawidłowej wersji.

local/index.ts

const localHomeSdk = new App('1.0.2');

Po naprawieniu błędu skompiluj aplikację i wdróż ją ponownie w Firebase. W app-faulty/local uruchom:

$ npm run build
$ firebase deploy --only hosting

Testowanie poprawki

Po wdrożeniu uruchom ponownie urządzenie Google Home, aby mogło wczytać zaktualizowaną aplikację Local Home. Upewnij się, że wersja aplikacji Local Home to 1.0.2. Tym razem w konsoli Narzędzi deweloperskich w Chrome nie powinny się pojawiać żadne błędy.

c8456f7b5f77f894.png

Teraz możesz ponownie spróbować wysłać polecenia do urządzenia.

„OK Google, wymuś lokalne”.

„OK Google, zatrzymaj pralkę”.

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

„OK Google, wymuś domyślne”.

6. Uruchamianie pakietu Test Suite for Smart Home

Po zweryfikowaniu urządzenia za pomocą sterowania dotykowego w aplikacji Google Home lub poleceń głosowych możesz użyć zautomatyzowanego pakietu Test Suite for smart home, aby sprawdzić przypadki użycia na podstawie typów urządzeń i cech powiązanych z integracją. Pakiet Test Suite przeprowadza serię testów, aby wykryć problemy w integracji, i wyświetla informacyjne komunikaty o nieudanych przypadkach testowych, aby przyspieszyć debugowanie przed przejrzeniem logów zdarzeń.

Uruchamianie pakietu testów dla inteligentnego domu

Aby przetestować integrację typu chmura-chmura za pomocą pakietu Test Suite:

  1. W przeglądarce internetowej otwórz pakiet Test Suite for smart home.
  2. Zaloguj się w Google za pomocą przycisku w prawym górnym rogu. Umożliwi to pakietowi Test Suite wysyłanie poleceń bezpośrednio do Asystenta Google.
  3. W polu Identyfikator projektu wpisz identyfikator projektu integracji typu chmura-chmura. Następnie kliknij DALEJ.
  4. W kroku Ustawienia testu w sekcji Urządzenia i cechy powinna się wyświetlić pralka Faulty Washer.
  5. Wyłącz opcję Test Request Sync , ponieważ przykładowa aplikacja pralki nie ma interfejsu użytkownika do dodawania, usuwania ani zmieniania nazwy pralki. W systemie produkcyjnym musisz wywoływać funkcję Request Sync za każdym razem, gdy użytkownik dodaje, usuwa lub zmienia nazwę urządzeń.
  6. Pozostaw włączoną opcję Local Home SDK , ponieważ będziemy testować ścieżki lokalne i w chmurze.
  7. Aby rozpocząć testowanie, kliknij Dalej: środowisko testowe.

67433d9190fa770e.png

Po zakończeniu testów zauważysz, że testy wstrzymywania/wznawiania w ścieżce lokalnej kończą się niepowodzeniem, a testy wstrzymywania/wznawiania w ścieżce w chmurze – powodzeniem.

d1ebd5cfae2a2a47.png

Analizowanie komunikatu o błędzie

Przyjrzyj się bliżej komunikatom o błędach w nieudanych przypadkach testowych. Informują one o oczekiwanym stanie w przypadku danego testu i o rzeczywistym stanie. W tym przypadku w przypadku testu „Wstrzymaj pralkę” oczekiwany stan to isPaused: true, ale w rzeczywistym stanie otrzymaliśmy isPaused: false. Podobnie w przypadku testu „Wstrzymaj pralkę” oczekiwany stan to isPaused: true, ale w rzeczywistym stanie otrzymaliśmy isPaused: false.

6bfd3acef9c16b84.png

Z komunikatów o błędach wynika, że w ścieżce lokalnej ustawiamy stan isPaused odwrotnie.

Identyfikowanie i naprawianie błędu

Znajdźmy kod źródłowy, w którym aplikacja Home wysyła polecenie wykonania do urządzenia. getDataCommand() to funkcja wywoływana przez executeHandler() w celu ustawienia payload w poleceniu wykonania wysyłanym do urządzenia.

local/index.ts

getDataForCommand(command: string, params: IWasherParams): unknown {
    switch (command) {
        case 'action.devices.commands.OnOff':
            return {
                on: params.on ? true : false
            };
        case 'action.devices.commands.StartStop':
            return {
                isRunning: params.start ? true : false
            };
        case 'action.devices.commands.PauseUnpause':
            return {
                // Is there something wrong here?
                isPaused: params.pause ? false : true
            };
        default:
            console.error('Unknown command', command);
            return {};
    }
}

Rzeczywiście ustawiamy isPause w stanie odwrotnym. Powinno być ustawione na true, gdy params.pause ma wartość true, a w przeciwnym razie na false. Naprawmy to.

local/index.ts

getDataForCommand(command: string, params: IWasherParams): unknown {
    switch (command) {
        case 'action.devices.commands.OnOff':
            return {
                on: params.on ? true : false
            };
        case 'action.devices.commands.StartStop':
            return {
                isRunning: params.start ? true : false
            };
        case 'action.devices.commands.PauseUnpause':
            return {
                isPaused: params.pause ? true : false
            };
        default:
            console.error('Unknown command', command);
            return {};
    }
}

Zmień wersję aplikacji Local Home, abyśmy mogli sprawdzić, czy używamy prawidłowej wersji.

local/index.ts

const localHomeSdk = new App('1.0.3');

Pamiętaj, aby ponownie skompilować aplikację i wdrożyć ją w Firebase. W app-faulty/local uruchom:

$ npm run build
$ firebase deploy --only hosting

Teraz uruchom ponownie urządzenie Google Home, aby mogło wczytać zaktualizowaną aplikację Local Home. Upewnij się, że wersja aplikacji Local Home to 1.0.3.

Testowanie poprawki

Teraz ponownie uruchom zestaw testów dla inteligentnego domu z tymi samymi konfiguracjami. Zobaczysz, że wszystkie przypadki testowe zostały zaliczone.

b7fc8c5d3c727d8d.png

7. Gratulacje

764dbc83b95782a.png

Gratulacje! Wiesz już, jak rozwiązywać problemy z aplikacją Home za pomocą pakietu Test Suite for smart home i Cloud Logging.

Więcej informacji

Oto kilka dodatkowych rzeczy, które możesz wypróbować:

Możesz też dowiedzieć się więcej o testowaniu i przesyłaniu integracji do sprawdzenia, w tym o procesie certyfikacji, który umożliwia opublikowanie integracji dla użytkowników.