Willkommen beim Google Home Developer Center, der neuen Anlaufstelle für Smart-Home-Aktionen. Hinweis:Sie erstellen weiterhin Aktionen in der Actions Console.

Lokale Auftragsausführungs-App implementieren

Mit Sammlungen den Überblick behalten Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.

Zur Unterstützung der lokalen Auftragsausführung müssen Sie eine App für die folgenden Smart-Home-Intents erstellen:

  • IDENTIFY: Unterstützt die Erkennung von lokal steuerbaren Smart-Geräten. Der Intent-Handler extrahiert Daten, die Ihr Smart-Home-Gerät während der Erkennung zurückgibt, und sendet diese als Antwort an Google.
  • EXECUTE: Unterstützt die Ausführung von Befehlen.
  • QUERY: Unterstützt die Abfrage des Gerätestatus.
  • REACHABLE_DEVICES (optional): Unterstützt die Erkennung von lokal steuerbaren Endgeräten hinter einem Hub (oder einer Bridge).

Diese App wird auf Google Home- oder Google Nest-Geräten von Nutzern ausgeführt und verbindet dein Smart-Home-Gerät mit Assistant. Sie können die Anwendung mit TypeScript (bevorzugt) oder JavaScript erstellen.

TypeScript wird empfohlen, da Sie mithilfe von Bindungen statisch dafür sorgen können, dass die von Ihrer Anwendung zurückgegebenen Daten mit den von der Plattform erwarteten Typen übereinstimmen.

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

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

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

Zum Bereitstellen Ihrer Anwendung für die lokale Auftragsausführung müssen Sie ein JavaScript-Bundle für Ihren Code und alle zugehörigen Abhängigkeiten erstellen.

Verwenden Sie die Projektinitialisierung der lokalen Auftragsausführungsanwendung, um ein Bootstrapping für die entsprechende Projektstruktur mit Ihrer bevorzugten Bundler-Konfiguration durchzuführen.

Projektvorlagen

Führen Sie zum Auswählen der Bundler-Konfiguration den Befehl npm init aus, wie in den folgenden Beispielen gezeigt:

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 das lokale App-Projekt für die Auftragsausführung enthält.

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 das lokale App-Projekt für die Auftragsausführung enthält.

Roll-up

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 das lokale App-Projekt für die Auftragsausführung enthält.

Parzelle

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 das lokale App-Projekt für die Auftragsausführung enthält.

Häufige Aufgaben auf Projektebene ausführen

Das generierte Projekt unterstützt die folgenden npm-Skripts:

Set
cd project-directory/
npm run build

Mit diesem Skript wird die TypeScript-Quelle kompiliert und Ihre Anwendung mit ihren Abhängigkeiten für die Chrome-Laufzeitumgebung im Unterverzeichnis dist/web und die Node.js-Laufzeitumgebung im Unterverzeichnis dist/node gebündelt.

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

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

Bereitstellen
cd project-directory/
npm run start

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

IDENTIFY-Handler implementieren

Der IDENTIFY-Handler wird ausgelöst, wenn das Google Home- oder Google Nest-Gerät neu gestartet wird und nicht bestätigte lokale Geräte angezeigt werden, einschließlich Endgeräten, die mit einem Hub verbunden sind. Die Local Home Platform sucht anhand der zuvor angegebenen Informationen zur Scankonfiguration nach lokalen Geräten und ruft Ihren IDENTIFY-Handler mit den Scanergebnissen auf.

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

Wenn die Scanergebnisse Ihrem Gerät entsprechen, sollte der IDENTIFY-Handler ein IdentifyResponsePayload-Objekt zurückgeben, das ein device-Objekt mit Smart-Home-Metadaten enthält (z. B. Typen, Merkmale und Berichtsstatus).

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

Beispiel

Die folgenden Snippets zeigen, wie Sie IDENTIFY-Handler für eigenständige Geräte- bzw. Hub-Integrationen erstellen können.

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 identifizieren

Wenn Google ein Hub-Gerät erkennt, behandelt es den Hub als Kanal für die verbundenen Endgeräte des Hubs und versucht, diese Endgeräte zu überprüfen.

Folgen Sie der Anleitung für Ihren IDENTIFY-Handler, damit Google prüfen kann, ob ein Hub-Gerät vorhanden ist:

  • Wenn die Antwort SYNC die IDs lokaler Endgeräte meldet, die mit dem Hub verbunden sind, legen Sie isProxy im IdentifyResponsePayload als true fest.
  • Wenn Ihre Antwort SYNC Ihr Hub-Gerät nicht meldet, legen Sie isLocalOnly im IdentifyResponsePayload als true fest.
  • 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, welche Endgeräte lokal gesteuert werden können. Dieser Intent wird jedes Mal ausgelöst, wenn Google einen Discovery-Scan ausführt (etwa einmal pro Minute), solange erkannt wird, dass der Hub online ist.

Sie implementieren den REACHABLE_DEVICES-Handler ähnlich wie den IDENTIFY-Handler, mit der Ausnahme, dass Ihr Handler zusätzliche Geräte-IDs erfassen muss, die vom lokalen Proxy-Gerät (dem Hub) erreicht werden können. Das Feld device.verificationId enthält die lokale Geräte-ID für ein Endgerät, das mit dem Hub verbunden ist.

Der ReachableDevicesRequest von der lokalen Startseite enthält eine Instanz von LocalIdentifiedDevice. Über diese Instanz können Sie die Proxy-Geräte-ID sowie Daten aus den Scanergebnissen abrufen.

Ihr REACHABLE_DEVICES-Handler sollte ein ReachableDevicesPayload-Objekt zurückgeben, das ein devices-Objekt enthält, das ein Array von verificationId-Werten enthält, die die Endgeräte repräsentieren, die vom Hub gesteuert werden. Die verificationId-Werte müssen mit einem der otherDeviceIds aus der SYNC-Antwort übereinstimmen.

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

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 das Local Home SDK, um über ein vorhandenes Protokoll auf Ihre Smart-Home-Geräte zuzugreifen.

Die Local Home Platform übergibt dieselbe Eingabenutzlast an die Handler-Funktion EXECUTE wie für den Intent EXECUTE an Ihre Cloud-Auftragsausführung. Ebenso gibt der EXECUTE-Handler Ausgabedaten im selben Format zurück wie bei der Verarbeitung des EXECUTE-Intents. Um die Antworterstellung zu vereinfachen, kannst du die Klasse Execute.Response.Builder des Local Home SDK verwenden.

Ihre App hat keinen direkten Zugriff auf die IP-Adresse des Geräts. Verwenden Sie stattdessen die Schnittstelle CommandRequest, um Befehle basierend auf einem dieser Protokolle zu erstellen: UDP, TCP oder HTTP. Dann rufen Sie die Funktion deviceManager.send() auf, um die Befehle zu senden.

Verwenden Sie beim Targeting von Befehlen auf Geräte die Geräte-ID (und ggf. die Parameter im Feld customData) der SYNC-Antwort, um mit dem Gerät zu kommunizieren.

Beispiel

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

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 das Local Home SDK, um den Status deiner Smart-Home-Geräte zu melden.

Die Local Home Platform übergibt die gleiche Nutzlast der Anfrage an die Handler-Funktion QUERY wie für den Intent QUERY an die Cloud-Auftragsausführung. Entsprechend gibt der QUERY-Handler Daten im selben Format zurück wie bei der Verarbeitung des QUERY-Intents.

Befehle an Geräte hinter einem Hub senden

Wenn Sie Endgeräte hinter einem Hub steuern möchten, müssen Sie möglicherweise zusätzliche Informationen in der protokollspezifischen Befehlsnutzlast angeben, die an den Hub gesendet wird, damit der Hub erkennen kann, auf welches Gerät der Befehl ausgerichtet ist. In einigen Fällen kann dies direkt aus dem Wert device.id abgeleitet werden. Wenn dies jedoch nicht der Fall ist, sollten Sie diese zusätzlichen Daten in das Feld customData aufnehmen.

Wenn Sie Ihre Anwendung mit TypeScript erstellt haben, denken Sie daran, die Anwendung in JavaScript zu kompilieren. Sie können das Codesystem Ihrer Wahl verwenden, um den Code zu schreiben. Prüfen Sie, ob Ihr Ziel vom Chrome-Browser unterstützt wird.