Wenn Sie die lokale Auftragsausführung unterstützen möchten, müssen Sie eine App erstellen, die die folgenden Smart-Home-Intents verarbeitet:
IDENTIFY
: Unterstützt die Suche nach lokal steuerbaren Smart-Home-Geräten. Der Intent-Handler extrahiert Daten, die Ihr Smart-Home-Gerät während der Erkennung zurückgibt, und sendet diese in einer 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 lokal steuerbarer Endgeräte hinter einem Hub (oder einer Bridge).
Diese App wird auf den Google Home- oder Google Nest-Geräten des Nutzers ausgeführt und verbindet Ihr Smart-Home-Gerät mit Assistant. Sie können die App mit TypeScript (bevorzugt) oder JavaScript erstellen.
TypeScript wird empfohlen, da Sie mit Bindungen statisch dafür sorgen können, dass die von Ihrer App zurückgegebenen Daten den von der Plattform erwarteten Typen entsprechen.
Weitere Informationen zur API finden Sie in der Referenz zur Local Home SDK API.
In den folgenden Snippets wird gezeigt, wie Sie die App für die lokale Auftragsausführung initialisieren und Ihre Handler anhängen.
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
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
Um Ihre App für die lokale Auftragsausführung bereitzustellen, müssen Sie ein JavaScript-Bundle für Ihren Code und alle zugehörigen Abhängigkeiten erstellen.
Verwenden Sie den Project Initializer der App für die lokale Ausführung, um die entsprechende Projektstruktur mit der gewünschten Bundler-Konfiguration zu erstellen.
Projektvorlagen
Führen Sie den Befehl npm init
aus, um die Bundler-Konfiguration auszuwählen, wie in den folgenden Beispielen gezeigt:
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 Projekt der App für die lokale Auftragsausführung enthält.
TypeScript mit webpack-Bündelkonfiguration:
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 Projekt der App für die lokale Auftragsausführung enthält.
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 Projekt der App für die lokale Auftragsausführung enthält.
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 Projekt der App für die lokale Auftragsausführung enthält.
Häufige Aufgaben auf Projektebene ausführen
Das generierte Projekt unterstützt die folgenden npm-Scripts:
cd project-directory/ npm run build
Dieses Script 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
.
cd project-directory/ npm run lint npm run compile npm test
Dieses Script überprüft die Syntax Ihres TypeScript-Codes, kompiliert ihn, ohne eine Ausgabe im Unterverzeichnis dist/
zu erzeugen, und führt automatisierte Tests von test.ts
aus.
cd project-directory/ npm run start
Während der Entwicklung werden Ihre App-Bundles für die Chrome- und Node.js-Laufzeitumgebungen lokal über dieses Script bereitgestellt.
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 erkennt (einschließlich Endgeräte, die mit einem Hub verbunden sind). Die Local Home-Plattform sucht anhand der zuvor angegebenen Scankonfigurationsinformationen nach lokalen Geräten und ruft Ihren IDENTIFY
-Handler mit den Scanergebnissen auf.
Die IdentifyRequest
von der Local Home-Plattform enthält die Scandaten einer LocalIdentifiedDevice
-Instanz. Es wird nur eine device
-Instanz basierend auf der Scankonfiguration ausgefüllt, mit der das Gerät gefunden wurde.
Wenn die Scanergebnisse mit Ihrem Gerät übereinstimmen, sollte Ihr IDENTIFY
-Handler ein IdentifyResponsePayload
-Objekt zurückgeben, das ein device
-Objekt mit Smart-Home-Metadaten (z. B. Typen, Merkmale und Berichtsstatus) enthält.
Google stellt eine Geräteverknüpfung her, wenn der verificationId
-Wert aus der IDENTIFY
-Antwort mit einem der otherDeviceIds
-Werte übereinstimmt, die in der SYNC
-Antwort zurückgegeben wurden.
Beispiel
Die folgenden Snippets zeigen, wie Sie IDENTIFY
-Handler für die Integration von eigenständigen Geräten bzw. Hubs erstellen können.
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; };
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 Verbindung zu den verbundenen Endgeräten des Hubs und versucht, diese Endgeräte zu bestätigen.
Damit Google prüfen kann, ob ein Hub-Gerät vorhanden ist, folge dieser Anleitung für deinen IDENTIFY
-Handler:
- Wenn in deiner
SYNC
-Antwort die IDs der lokalen Endgeräte angegeben sind, die mit dem Hub verbunden sind, setzeisProxy
inIdentifyResponsePayload
auftrue
. - Wenn in der
SYNC
-Antwort kein Hub-Gerät angegeben ist, setzeisLocalOnly
inIdentifyResponsePayload
auftrue
. - Das Feld
device.id
enthält die lokale Geräte-ID für das Hub-Gerät selbst.
Implementieren Sie den REACHABLE_DEVICES-Handler (nur Hub-Integrationen)
Die REACHABLE_DEVICES
-Intent 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 durchführt (ungefähr einmal pro Minute), sofern der Hub als online erkannt wird.
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 (d. h. dem Hub) erreichbar sind. Das Feld device.verificationId
enthält die lokale Geräte-ID eines Endgeräts, das mit dem Hub verbunden ist.
Die ReachableDevicesRequest
von der Local Home-Plattform enthält eine Instanz von LocalIdentifiedDevice
.
Über diese Instanz können Sie die Proxy-Geräte-ID sowie Daten aus den Scanergebnissen abrufen.
Der REACHABLE_DEVICES
-Handler sollte ein ReachableDevicesPayload
-Objekt zurückgeben, das ein devices
-Objekt mit einem Array von verificationId
-Werten enthält, die die Endgeräte darstellen, die vom Hub gesteuert werden. Die verificationId
-Werte müssen mit einem der otherDeviceIds
-Werte aus der SYNC
-Antwort übereinstimmen.
Das folgende Snippet zeigt, wie Sie einen REACHABLE_DEVICES
-Handler erstellen können.
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-Plattform übergibt der EXECUTE
-Handlerfunktion dieselbe Eingaben-Nutzlast wie für den EXECUTE
-Intent an die Cloud-Ausführung. Ebenso gibt Ihr EXECUTE
-Handler Ausgabedaten im selben Format zurück wie bei der Verarbeitung der EXECUTE
-Intention.
Um die Erstellung von Antworten zu vereinfachen, können Sie 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 Benutzeroberfläche CommandRequest
, um Befehle auf der Grundlage eines der folgenden Protokolle zu erstellen: UDP, TCP oder HTTP. Rufen Sie dann die Funktion deviceManager.send()
auf, um die Befehle zu senden.
Wenn Sie Befehle auf Geräte ausrichten, verwenden Sie die Geräte-ID (und gegebenenfalls Parameter aus dem Feld customData
) aus der SYNC
-Antwort, um mit dem Gerät zu kommunizieren.
Beispiel
Das folgende Code-Snippet zeigt, wie du einen EXECUTE
-Handler erstellen könntest.
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
Ihr QUERY
-Handler in der App verarbeitet Nutzeranfragen und verwendet das Local Home SDK, um den Status Ihrer Smart-Home-Geräte zu melden.
Die Local Home-Plattform übergibt der Handlerfunktion „QUERY“ dieselbe Anfragen-Nutzlast wie für die QUERY
-Intention an die Cloud-Ausführung. Ebenso gibt Ihr QUERY
-Handler Daten im selben Format zurück wie bei der Verarbeitung der QUERY
-Intent.
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, für welches Gerät der Befehl bestimmt ist. In einigen Fällen kann dies direkt aus dem Wert device.id
abgeleitet werden. Ist dies nicht der Fall, sollten Sie diese zusätzlichen Daten im Feld customData
angeben.
Wenn Sie Ihre App mit TypeScript erstellt haben, müssen Sie sie in JavaScript kompilieren. Sie können das Modulsystem Ihrer Wahl verwenden, um Ihren Code zu schreiben. Das Ziel muss vom Chrome-Browser unterstützt werden.