Lokale Fulfillment-App implementieren

Um die lokale Auftragsausführung zu unterstützen, müssen Sie eine App für diese Smart-Home-Intents:

  • IDENTIFY: Unterstützt die Erkennung lokal steuerbarer Smart-Home-Geräte. Die Intent-Handler extrahiert Daten, die dein Smart-Home-Gerät während der Erkennung zurückgibt und als Antwort an Google gesendet.
  • EXECUTE: Unterstützt die Ausführung von Befehlen.
  • QUERY: Unterstützt die Abfrage des Gerätestatus.
  • REACHABLE_DEVICES (optional): Unterstützt die Erkennung lokal steuerbarer Elemente hinter einem Hub- oder Bridge-Gerät.

Diese App wird auf den Google Home- oder Google Nest-Geräten des Nutzers ausgeführt und verbindet Ihr Smart-Home-Gerät mit Assistent. Sie können die App mit TypeScript (bevorzugt) oder JavaScript erstellen.

TypeScript wird empfohlen, weil Sie Bindungen um statisch sicherzustellen, dass die von Ihrer App zurückgegebenen Daten den Typen entsprechen, die die Plattform erwartet.

Weitere Informationen zur API finden Sie in der Local Home SDK API-Referenz

Die folgenden Snippets zeigen, wie Sie die App für die lokale Auftragsausführung initialisieren und Ihre Handler anhängen.

<ph type="x-smartling-placeholder">
</ph>
Eigenständig
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");
  });

Projekt erstellen

Damit Sie Ihre lokale App für die Auftragsausführung bereitstellen können, müssen Sie ein JavaScript-Bundle erstellen. für Ihren Code und alle zugehörigen Abhängigkeiten.

Verwenden Sie das Projekt der lokalen App für die Auftragsausführung Initialisierer Zum Bootstrapping der geeigneten Projektstruktur mit Ihrem bevorzugten Bundler Konfiguration.

Projektvorlagen

Um Ihre Bundler-Konfiguration auszuwählen, führen Sie den Befehl npm init aus, wie in der folgende Beispiele:

<ph type="x-smartling-placeholder">
</ph>
Keine

TypeScript ohne Bundler-Konfiguration:

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

Projektstruktur:

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

Ersetzen Sie project-directory durch ein neues Verzeichnis, das den Projekt für die lokale Auftragsausführung.

Webpack

TypeScript mit Webpack-Bundler Konfiguration:

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

Projektstruktur:

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

Ersetzen Sie project-directory durch ein neues Verzeichnis, das den Projekt für die lokale Auftragsausführung.

Sammeln

TypeScript mit Rollup Bundler-Konfiguration:

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

Projektstruktur:

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

Ersetzen Sie project-directory durch ein neues Verzeichnis, das den Projekt für die lokale Auftragsausführung.

Paket

TypeScript mit Parcel Bundler-Konfiguration:

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

Projektstruktur:

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

Ersetzen Sie project-directory durch ein neues Verzeichnis, das den Projekt für die lokale Auftragsausführung.

Häufige Aufgaben auf Projektebene ausführen

Das generierte Projekt unterstützt die folgende npm-Funktion Skripts:

<ph type="x-smartling-placeholder">
</ph>
Set
cd project-directory/
npm run build

Dieses Skript kompiliert die TypeScript-Quelle und bündelt Ihre App mit ihren Abhängigkeiten für die Chrome-Laufzeitumgebung im Unterverzeichnis dist/web und die Node.js-Laufzeitumgebung im Unterverzeichnis dist/node.

Bestätigen
cd project-directory/
npm run lint
npm run compile
npm test

Dieses Skript überprüft die Syntax Ihres TypeScript-Codes, kompiliert ihn, ohne eine Ausgabe im Unterverzeichnis dist/ zu erzeugen, und führt automatisierte Tests über test.ts aus.

Bedienung
cd project-directory/
npm run start

Während der Entwicklung stellt dieses Skript Ihre App Bundles für die Chrome- und Node.js-Laufzeitumgebungen lokal bereit.

IDENTIFY-Handler implementieren

Der IDENTIFY-Handler wird ausgelöst, wenn das Google Home- oder Google Nest-Gerät neu startet und nicht verifizierte lokale Geräte erkennt, einschließlich Endgeräten, die mit einem Hub verbunden sind. Die Die Local Home-Plattform sucht anhand der Scankonfigurationsinformationen nach lokalen Geräten und rufen Sie den IDENTIFY-Handler mit den Scanergebnissen auf.

Die IdentifyRequest von der Local Home-Plattform, enthält die Scandaten eines LocalIdentifiedDevice Instanz. Basierend auf der Scankonfiguration wird nur eine device-Instanz ausgefüllt der das Gerät gefunden hat.

Wenn die Scanergebnisse mit Ihrem Gerät übereinstimmen, sollte der IDENTIFY-Handler eine IdentifyResponsePayload -Objekt, das ein device-Objekt mit Smart-Home-Metadaten (z. B. Typen, Eigenschaften und Berichtsstatus)

Google stellt eine Geräteverknüpfung her, wenn Der verificationId aus der IDENTIFY-Antwort stimmt mit einem der otherDeviceIds-Werte, die von der SYNC-Antwort zurückgegeben werden.

Beispiel

Die folgenden Snippets veranschaulichen, wie Sie IDENTIFY-Handler für eigenständige Geräte bzw. Hub-Integrationen.

<ph type="x-smartling-placeholder">
</ph>
Eigenständig
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;
  };

Geräte hinter einem Hub erkennen

Wenn Google ein Hub-Gerät erkennt, wird dieser als Conduit betrachtet. mit den verbundenen Endgeräten des Hubs und versuchen Sie, diese zu bestätigen.

So kann Google prüfen, ob ein Hub-Gerät vorhanden ist: für Ihren IDENTIFY-Handler:

  • Wenn Ihre SYNC-Antwort die IDs lokaler Endgeräte meldet, die mit dem isProxy trueim IdentifyResponsePayload
  • Wenn deine SYNC-Antwort dein Hub-Gerät nicht meldet, richte isLocalOnly als true in der IdentifyResponsePayload
  • Das Feld device.id enthält die lokale Geräte-ID für das Hub-Gerät selbst.

REACHABLE_devices-Handler implementieren (nur Hub-Integrationen)

Der Intent REACHABLE_DEVICES wird von Google gesendet, um zu bestätigen, auf welchen Endgeräten lokal gesteuert werden können. Dieser Intent wird jedes Mal ausgelöst, wenn Google einen Discovery-Scan (etwa einmal pro Minute), solange der Hub erkannt wird, online sein.

Der Handler REACHABLE_DEVICES wird ähnlich wie der Handler IDENTIFY implementiert. Handler bereitgestellt, mit der Ausnahme, dass der Handler zusätzliche Geräte-IDs erfassen muss die über den lokalen Proxy (d. h. den Hub) erreichbar sind. Die Das Feld device.verificationId enthält die lokale Geräte-ID für ein Endgerät der mit dem Hub verbunden ist.

Die ReachableDevicesRequest von der Local Home-Plattform enthält eine Instanz LocalIdentifiedDevice Über diese Instanz können Sie die Proxy-Geräte-ID sowie Daten von die Scanergebnisse.

Der REACHABLE_DEVICES-Handler sollte eine ReachableDevicesPayload , das ein devices-Objekt enthält, das ein Array von verificationId-Werte für die Endgeräte, die der Hub steuert. Die verificationId-Werte müssen mit einem der otherDeviceIds-Werte aus der SYNC-Antwort.

Das folgende Snippet zeigt, wie Sie ein REACHABLE_DEVICES erstellen können. -Handler.

<ph type="x-smartling-placeholder">
</ph>
Hub
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;
  };

EXECUTE-Handler implementieren

Der EXECUTE-Handler in der App verarbeitet Nutzerbefehle und verwendet die Local Home SDK, um über ein vorhandenes Protokoll auf deine Smart-Home-Geräte zuzugreifen.

Die „Local Home“-Plattform übergibt dieselbe Eingabenutzlast an den EXECUTE-Handler wie für EXECUTE auf die Cloud-Ausführung konzentrieren. Ebenso gibt der EXECUTE-Handler Ausgabedaten im selben Format wie bei der Verarbeitung des Intents EXECUTE. Um das Erstellen von Antworten zu vereinfachen, können Sie den Execute.Response.Builder Klasse, die das Local Home SDK bietet.

Ihre App hat keinen direkten Zugriff auf die IP-Adresse des Geräts. Stattdessen verwenden Sie die CommandRequest Schnittstelle, um Befehle zu erstellen, die auf einem der folgenden Protokolle basieren: UDP, TCP oder HTTP. Rufen Sie dann die Methode deviceManager.send() zum Senden der Befehle.

Beim Targeting von Befehlen auf Geräte verwenden Sie die Geräte-ID (und die Parameter aus dem customData-Feld, falls enthalten, aus der SYNC-Antwort, um zu kommunizieren mit dem Gerät.

Beispiel

Das folgende Code-Snippet zeigt, wie Sie den EXECUTE-Handler erstellen können.

<ph type="x-smartling-placeholder">
</ph>
Eigenständig/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());
  };

QUERY-Handler implementieren

Der QUERY-Handler in der App verarbeitet Nutzeranfragen und verwendet die Methode Local Home SDK, um den Status deiner Smart-Home-Geräte zu melden.

Die „Local Home“-Plattform übergibt die gleiche Anfragenutzlast an die „QUERY“. Handler wie für QUERY auf die Cloud-Ausführung konzentrieren. Ebenso gibt der QUERY-Handler Daten zurück im selben Format wie bei der Verarbeitung des Intents QUERY.

Befehle an Geräte hinter einem Hub senden

Zur Steuerung von Endgeräten hinter einem Hub musst du eventuell zusätzliche Informationen angeben in der protokollspezifischen Befehlsnutzlast, die an den Hub gesendet wird, um zu ermitteln, für welches Gerät der Befehl bestimmt ist. In einigen Fällen kann dies device.id direkt abgeleitet. Sollte dies jedoch nicht der Fall sein, sollten Sie diese zusätzlichen Daten in das Feld customData einfügen.

Wenn Sie Ihre App mit TypeScript erstellt haben, denken Sie daran, sie zu kompilieren, JavaScript Sie können das Modulsystem Ihrer Wahl verwenden, um Ihren Code zu schreiben. Prüfen Sie, ob das Ziel vom Chrome-Browser unterstützt wird.