Witamy w Google Home Developer Center – nowym miejscu, z którego dowiesz się, jak tworzyć inteligentne działania domowe. Uwaga: nadal będziesz tworzyć działania w konsoli Actions.

Wdrażanie lokalnej aplikacji do realizacji zamówień

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Aby umożliwić realizację zamówień lokalnych, musisz utworzyć aplikację, która będzie obsługiwać te inteligentne zamiary związane z domem:

  • IDENTIFY: obsługuje wykrywanie urządzeń, którymi można sterować lokalnie. Moduł obsługi intencji wyodrębnia dane, które urządzenie zwraca podczas wykrywania, i wysyła w odpowiedzi do Google.
  • EXECUTE: obsługuje wykonywanie poleceń.
  • QUERY: obsługuje zapytania dotyczące stanu urządzenia.
  • REACHABLE_DEVICES: (opcjonalnie) obsługuje wykrywanie urządzeń dostępnych lokalnie, które można kontrolować za pomocą hubu (lub mostka).

Ta aplikacja działa na urządzeniach Google Home lub Google Nest użytkownika i łączy Twoje urządzenie z Asystentem. Aplikację możesz utworzyć przy użyciu TypeScript (preferowanego) lub JavaScriptu.

Zalecamy używanie TypeScript, ponieważ można użyć powiązań, aby statycznie mieć pewność, że zwracane dane są zgodne z oczekiwanymi przez platformę.

Więcej informacji o interfejsie API znajdziesz w dokumentacji API pakietu Home Home SDK.

Poniższe fragmenty kodu pokazują, jak zainicjować lokalną aplikację do realizacji zamówień i dołączać moduły obsługi.

Oddzielne
import App = smarthome.App;
const localHomeApp: App = new App("1.0.0");
localHomeApp
  .onIdentify(identifyHandler)
  .onExecute(executeHandler)
  .listen()
  .then(() => {
    console.log("Ready");
  });
Hub
import App = smarthome.App;
const localHomeApp: App = new App("1.0.0");
localHomeApp
  .onIdentify(identifyHandler)
  .onReachableDevices(reachableDevicesHandler)
  .onExecute(executeHandler)
  .listen()
  .then(() => {
    console.log("Ready");
  });

Tworzenie projektu

Aby wdrożyć lokalną aplikację do realizacji zamówień, musisz utworzyć pakiet JavaScript dla swojego kodu i wszystkich jego zależności.

Użyj inicjatora projektu lokalnej aplikacji do realizacji zamówień, aby pobrać odpowiednią strukturę projektu z preferowaną konfiguracją pakietu.

Szablony projektów

Aby wybrać konfigurację pakietu, uruchom polecenie npm init zgodnie z tymi przykładami:

Brak

Skrypt TypeScript bez konfiguracji pakietu:

npm init @google/local-home-app project-directory/ --bundler none

Struktura projektu:

project-directory/
├── node_modules/
├── package.json
├── .gitignore
├── index.ts
├── test.ts
├── tsconfig.json
├── tslint.json
└── serve.js

Zastąp project-directory nowym katalogiem, który będzie zawierał lokalny projekt realizacji zamówień.

Pakiet internetowy

Skrypt TypeScript z konfiguracją pakietu webpack:

npm init @google/local-home-app project-directory/ --bundler webpack

Struktura projektu:

project-directory/
├── node_modules/
├── package.json
├── .gitignore
├── index.ts
├── test.ts
├── tsconfig.json
├── tslint.json
├── webpack.config.web.js
├── webpack.config.node.js
└── serve.js

Zastąp project-directory nowym katalogiem, który będzie zawierał lokalny projekt realizacji zamówień.

Pełny zakres

Skrypt Type Script z konfiguracją o pełnym zakresie:

npm init @google/local-home-app project-directory/ --bundler rollup

Struktura projektu:

project-directory/
├── node_modules/
├── package.json
├── .gitignore
├── index.ts
├── test.ts
├── tsconfig.json
├── tslint.json
├── rollup.config.js
└── serve.js

Zastąp project-directory nowym katalogiem, który będzie zawierał lokalny projekt realizacji zamówień.

Przesyłki

Skrypt Type Script z konfiguracją pakietu Parcel:

npm init @google/local-home-app project-directory/ --bundler parcel

Struktura projektu:

project-directory/
├── node_modules/
├── package.json
├── .gitignore
├── index.ts
├── test.ts
├── tsconfig.json
├── tslint.json
└── serve.js

Zastąp project-directory nowym katalogiem, który będzie zawierał lokalny projekt realizacji zamówień.

Wykonywanie typowych zadań na poziomie projektu

Wygenerowany projekt obsługuje te skrypty npm:

Pakiet
cd project-directory/
npm run build

Ten skrypt kompiluje źródło TypeScript i łączy aplikację z zależnościami środowiska wykonawczego Chrome w podkatalogu dist/web oraz środowiska wykonawczego Node.js w podkatalogu dist/node.

Zweryfikuj
cd project-directory/
npm run lint
npm run compile
npm test

Skrypt weryfikuje składnię kodu TypeScript, kompiluje go bez generowania danych wyjściowych w podkatalogu dist/ i uruchamia automatyczne testy aplikacji test.ts.

Wyświetlaj
cd project-directory/
npm run start

Podczas programowania ten skrypt lokalnie udostępnia pakiety aplikacji na środowiska wykonawcze Chrome i Node.js.

Zaimplementuj moduł obsługi IDENTIFY

Moduł obsługi IDENTIFY zostanie aktywowany, gdy urządzenie Google Home lub Google Nest uruchomi się ponownie i zauważy niezweryfikowane urządzenia lokalne (w tym urządzenia końcowe połączone z koncentratorem). Platforma lokalna skanuje urządzenia lokalne na podstawie podanych wcześniej informacji o konfiguracji skanowania i wywołuje Twój moduł obsługi IDENTIFY wraz z wynikami skanowania.

IdentifyRequest z platformy lokalnej strony głównej zawiera dane skanowania instancji LocalIdentifiedDevice. Na podstawie konfiguracji skanowania, która wykryła urządzenie, zostało wypełnione tylko jedno wystąpienie device.

Jeśli wyniki skanowania pasują do urządzenia, moduł obsługi IDENTIFY powinien zwracać obiekt IdentifyResponsePayload, który zawiera obiekt device z inteligentnymi metadanymi domu (takimi jak typ, cechy i stan raportu).

Google tworzy powiązanie urządzenia, jeśli verificationId w odpowiedzi IDENTIFY odpowiada jednej z wartości otherDeviceIds zwróconych przez odpowiedź SYNC.

Przykład

Poniższe fragmenty kodu pokazują, jak możesz utworzyć moduły obsługi IDENTIFY na potrzeby samodzielnych urządzeń i integracji hubu.

Oddzielne
const identifyHandler = (request: IntentFlow.IdentifyRequest):
  IntentFlow.IdentifyResponse => {

    // Obtain scan data from protocol defined in your scan config
    const device = request.inputs[0].payload.device;
    if (device.udpScanData === undefined) {
      throw Error("Missing discovery response");
    }
    const scanData = device.udpScanData.data;

    // Decode scan data to obtain metadata about local device
    const verificationId = "local-device-id";

    // Return a response
    const response: IntentFlow.IdentifyResponse = {
      intent: Intents.IDENTIFY,
      requestId: request.requestId,
      payload: {
        device: {
          id: device.id || "",
          verificationId, // Must match otherDeviceIds in SYNC response
        },
      },
    };
    return response;
  };
Hub
const identifyHandler = (request: IntentFlow.IdentifyRequest):
  IntentFlow.IdentifyResponse => {

    // Obtain scan data from protocol defined in your scan config
    const device = request.inputs[0].payload.device;
    if (device.udpScanData === undefined) {
      throw Error("Missing discovery response");
    }
    const scanData = device.udpScanData.data;

    // Decode scan data to obtain metadata about local device
    const proxyDeviceId = "local-hub-id";

    // Return a response
    const response: IntentFlow.IdentifyResponse = {
      intent: Intents.IDENTIFY,
      requestId: request.requestId,
      payload: {
        device: {
          id: proxyDeviceId,
          isProxy: true,     // Device can control other local devices
          isLocalOnly: true, // Device not present in `SYNC` response
        },
      },
    };
    return response;
  };

Identyfikowanie urządzeń w centrum

Jeśli Google wykryje urządzenie hubu, potraktuje je jak kanał zasilający połączone z nim urządzenia końcowe i spróbuje je zweryfikować.

Aby umożliwić Google sprawdzenie, czy urządzenie Hub jest dostępne, wykonaj te czynności dotyczące modułu obsługi IDENTIFY:

  • Jeśli odpowiedź SYNC zawiera identyfikatory lokalnych urządzeń końcowych połączonych z centrum, ustaw isProxy na true w IdentifyResponsePayload.
  • Jeśli odpowiedź SYNC nie zgłasza urządzenia Hub, ustaw isLocalOnly jako true w IdentifyResponsePayload.
  • Pole device.id zawiera identyfikator lokalnego urządzenia centralnego.

Zaimplementuj moduł obsługi REACHABLE_DEVICES (tylko integracja z centrum)

Intencja REACHABLE_DEVICES jest wysyłana przez Google w celu potwierdzenia, które urządzenia można kontrolować lokalnie. Ta intencja jest wywoływana za każdym razem, gdy Google uruchomi skanowanie wykrywające (mniej więcej raz na minutę), o ile system wykryje, że centrum jest online.

Stosujesz moduł obsługi REACHABLE_DEVICES w podobny sposób jak w przypadku modułu obsługi IDENTIFY. Różnica polega na tym, że Twój moduł obsługi musi zbierać dodatkowe identyfikatory urządzeń, do których może uzyskać dostęp lokalny serwer proxy (czyli centrum). Pole device.verificationId zawiera lokalny identyfikator urządzenia podłączonego do centrum.

ReachableDevicesRequest z platformy lokalnej strony głównej zawiera instancję LocalIdentifiedDevice. W ten sposób możesz uzyskać identyfikator urządzenia proxy i dane z wyników skanowania.

Twój moduł obsługi REACHABLE_DEVICES powinien zwracać obiekt ReachableDevicesPayload zawierający obiekt devices z tablicą wartości verificationId reprezentujących urządzenia końcowe, które kontroluje centrum. Wartości verificationId muszą odpowiadać jednej z wartości otherDeviceIds w odpowiedzi SYNC.

Fragment kodu poniżej pokazuje, jak utworzyć obsługę modułu REACHABLE_DEVICES.

Centrum
const reachableDevicesHandler = (request: IntentFlow.ReachableDevicesRequest):
  IntentFlow.ReachableDevicesResponse => {

    // Reference to the local proxy device
    const proxyDeviceId = request.inputs[0].payload.device.id;

    // Gather additional device ids reachable by local proxy device
    // ...

    const reachableDevices = [
      // Each verificationId must match one of the otherDeviceIds
      // in the SYNC response
      { verificationId: "local-device-id-1" },
      { verificationId: "local-device-id-2" },
    ];

    // Return a response
    const response: IntentFlow.ReachableDevicesResponse = {
      intent: Intents.REACHABLE_DEVICES,
      requestId: request.requestId,
      payload: {
        devices: reachableDevices,
      },
    };
    return response;
  };

Wdrażanie modułu obsługi funkcji EXECUTE

Twój moduł obsługi EXECUTE w aplikacji przetwarza polecenia użytkowników i używa pakietu SDK Home Home, aby uzyskiwać dostęp do urządzeń w ramach istniejącego protokołu.

Platforma lokalna przekazuje ten sam ładunek wejściowy do funkcji obsługi EXECUTE, co w przypadku EXECUTE intencji do realizacji chmury. Analogicznie moduł obsługi EXECUTE zwraca dane wyjściowe w tym samym formacie co przetwarzanie intencji EXECUTE. Aby uprościć tworzenie odpowiedzi, możesz użyć klasy Execute.Response.Builder udostępnianej przez pakiet SDK pakietu Home Home.

Twoja aplikacja nie ma bezpośredniego dostępu do adresu IP urządzenia. Zamiast tego użyj interfejsu CommandRequest, aby utworzyć polecenia na podstawie jednego z tych protokołów: UDP, TCP lub HTTP. Następnie wywołaj funkcję deviceManager.send(), aby wysłać polecenia.

Podczas kierowania poleceń na urządzenia używaj identyfikatora urządzenia (wraz z parametrami z pola customData, jeśli jest podany) w odpowiedzi SYNC, aby komunikować się z urządzeniem.

Przykład

Fragment kodu poniżej pokazuje, jak możesz utworzyć moduł obsługi żądania EXECUTE.

Oddzielne/Hub
const executeHandler = (request: IntentFlow.ExecuteRequest):
  Promise<IntentFlow.ExecuteResponse> => {

    // Extract command(s) and device target(s) from request
    const command = request.inputs[0].payload.commands[0];
    const execution = command.execution[0];

    const response = new Execute.Response.Builder()
      .setRequestId(request.requestId);

    const result = command.devices.map((device) => {
      // Target id of the device provided in the SYNC response
      const deviceId = device.id;
      // Metadata for the device provided in the SYNC response
      // Use customData to provide additional required execution parameters
      const customData: any = device.customData;

      // Convert execution command into payload for local device
      let devicePayload: string;
      // ...

      // Construct a local device command over TCP
      const deviceCommand = new DataFlow.TcpRequestData();
      deviceCommand.requestId = request.requestId;
      deviceCommand.deviceId = deviceId;
      deviceCommand.data = devicePayload;
      deviceCommand.port = customData.port;
      deviceCommand.operation = Constants.TcpOperation.WRITE;

      // Send command to the local device
      return localHomeApp.getDeviceManager()
        .send(deviceCommand)
        .then((result) => {
          response.setSuccessState(result.deviceId, state);
        })
        .catch((err: IntentFlow.HandlerError) => {
          err.errorCode = err.errorCode || IntentFlow.ErrorCode.INVALID_REQUEST;
          response.setErrorState(device.id, err.errorCode);
        });
    });

    // Respond once all commands complete
    return Promise.all(result)
      .then(() => response.build());
  };

Wdrażanie modułu obsługi QUERY

Twój moduł obsługi QUERY w aplikacji przetwarza żądania użytkowników i za pomocą SDK lokalnego domu zgłasza stan Twoich urządzeń.

Platforma lokalna przekazuje ten sam ładunek żądania do funkcji obsługi zapytania „QUERY”, co w przypadku intencji QUERY w celu realizacji chmury. Analogicznie moduł obsługi QUERY zwraca dane w tym samym formacie co przetwarzanie intencji QUERY.

Wysyłanie poleceń do urządzeń za centrum

Aby sterować urządzeniami końcowymi za koncentratorem, może być konieczne podanie dodatkowych informacji w ładunku poleceń powiązanym z protokołem wysłanym do centrum w celu określenia, na które urządzenie jest przeznaczone polecenie. W niektórych przypadkach można to bezpośrednio wywnioskować z wartości device.id, ale gdy tak się nie dzieje, warto uwzględnić te dodatkowe dane w polu customData.

Jeśli Twoja aplikacja została utworzona za pomocą TypeScriptu, musisz skompilować ją w JavaScript. Do pisania kodu możesz użyć wybranego przez siebie systemu modułów. Upewnij się, że przeglądarka Chrome obsługuje docelowe wartości.