Um die lokale Auftragsausführung zu unterstützen, müssen Sie eine App erstellen, die diese Smart-Home-Intents verarbeitet:
IDENTIFY
: Unterstützt die Erkennung von 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 das Abfragen 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 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 Bindungen verwenden können, um statisch sicherzustellen, dass die von Ihrer App zurückgegebenen Daten den von der Plattform erwarteten Typen entsprechen.
Weitere Informationen zur API finden Sie in der API-Referenz für das Local Home SDK.
Die folgenden Snippets zeigen, wie Sie die lokale Fulfillment-App initialisieren und Ihre Handler anhängen können.
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
Damit Sie Ihre lokale Fulfillment-App bereitstellen können, müssen Sie ein JavaScript-Bundle für Ihren Code und alle seine Abhängigkeiten erstellen.
Verwenden Sie den Projektinitialisierer für die lokale Ausführung, um die entsprechende Projektstruktur mit Ihrer bevorzugten Bundler-Konfiguration zu booten.
Projektvorlagen
Führen Sie den Befehl npm init
aus, um Ihre 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 Local Fulfillment-App enthält.
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 Projekt der Local Fulfillment-App 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 Local Fulfillment-App 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 Local Fulfillment-App 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 Skript kompiliert TypeScript-Quellcode und bündelt Ihre App mit ihren Abhängigkeiten für die Chrome-Laufzeitumgebung im Unterverzeichnis dist/web
und für die Node.js-Laufzeitumgebung im Unterverzeichnis dist/node
.
cd project-directory/ npm run lint npm run compile npm test
Mit diesem Script wird die Syntax Ihres TypeScript-Codes überprüft, er wird kompiliert, ohne dass eine Ausgabe im Unterverzeichnis dist/
erfolgt, und es werden automatisierte Tests aus test.ts
ausgeführt.
cd project-directory/ npm run start
Während der Entwicklung stellt dieses Skript Ihre App-Bundles lokal für die Chrome- und Node.js-Laufzeitumgebungen bereit.
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 (einschließlich Endgeräte, die mit einem Hub verbunden sind) erkannt werden. Die Local Home-Plattform sucht nach lokalen Geräten anhand der von dir angegebenen Informationen zur Scan-Konfiguration und ruft deinen IDENTIFY
-Handler mit den Scanergebnissen auf.
Die IdentifyRequest
der Local Home-Plattform enthält die Scandaten einer LocalIdentifiedDevice
-Instanz. Es wird nur eine device
-Instanz ausgefüllt, basierend auf der Scankonfiguration, mit der das Gerät erkannt wurde.
Wenn die Scanergebnisse mit deinem Gerät übereinstimmen, sollte dein IDENTIFY
-Handler ein IdentifyResponsePayload
-Objekt zurückgeben, das ein device
-Objekt mit Smart-Home-Metadaten (z. B. Typen, Attributen und Berichtsstatus) enthält.
Google stellt eine Gerätezuordnung 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 Integrationen von Standalone-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, wird es als Verbindung zu den verbundenen Endgeräten des Hubs behandelt und es wird versucht, diese Endgeräte zu bestätigen.
Damit Google bestätigen kann, dass ein Hub-Gerät vorhanden ist, folgen Sie dieser Anleitung für Ihren IDENTIFY
-Handler:
- Wenn in der Antwort von
SYNC
die IDs der lokalen Endgeräte angegeben sind, die mit dem Hub verbunden sind, legen SieisProxy
alstrue
imIdentifyResponsePayload
fest. - Wenn in der
SYNC
-Antwort dein Hub-Gerät nicht angegeben ist, setzeisLocalOnly
in derIdentifyResponsePayload
auftrue
. - 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 Erkennungsscan ausführt (ungefähr einmal pro Minute), sofern der Hub als online erkannt wird.
Sie implementieren den REACHABLE_DEVICES
-Handler ähnlich wie den IDENTIFY
-Handler. Ihr Handler muss jedoch zusätzliche Geräte-IDs erfassen, die über das lokale Proxygerät (d. h. den Hub) erreichbar sind. Das Feld device.verificationId
enthält die lokale Geräte-ID für ein Endgerät, das mit dem Hub verbunden ist.
Die ReachableDevicesRequest
aus 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.
Ihr 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 der Hub steuert. Die verificationId
-Werte müssen mit einem der otherDeviceIds
-Werte aus der SYNC
-Antwort übereinstimmen.
Das folgende Snippet zeigt, wie Sie Ihren 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
Ihr EXECUTE
-Handler in der App verarbeitet Nutzerbefehle und greift mit dem Local Home SDK über ein vorhandenes Protokoll auf Ihre Smart-Home-Geräte zu.
Die Local Home-Plattform übergibt dieselbe Eingabe-Payload an die EXECUTE
-Handlerfunktion wie für den Intent EXECUTE
an Ihr Cloud-Fulfillment. Ebenso gibt Ihr EXECUTE
-Handler Ausgabedaten im selben Format wie bei der Verarbeitung des EXECUTE
-Intent zurück.
Um die Erstellung von Antworten zu vereinfachen, können Sie die Klasse Execute.Response.Builder
verwenden, die im Local Home SDK enthalten ist.
Ihre App hat keinen direkten Zugriff auf die IP-Adresse des Geräts. Verwenden Sie stattdessen die CommandRequest
-Schnittstelle, um Befehle basierend auf einem dieser Protokolle zu erstellen: UDP, TCP oder HTTP. Rufen Sie dann die Funktion deviceManager.send()
auf, um die Befehle zu senden.
Wenn Sie Befehle an Geräte senden, verwenden Sie die Geräte-ID (und Parameter aus dem Feld customData
, falls vorhanden) aus der SYNC
-Antwort, um mit dem Gerät zu kommunizieren.
Beispiel
Das folgende Code-Snippet zeigt, wie Sie Ihren EXECUTE
-Handler erstellen können.
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 meldet den Status Ihrer Smart-Home-Geräte über das Local Home SDK.
Die Local Home-Plattform übergibt dieselbe Anfrage-Payload an die Handler-Funktion für „QUERY“ wie für den Intent QUERY
an Ihr Cloud-Fulfillment. Ebenso gibt Ihr QUERY
-Handler Daten im selben Format wie bei der Verarbeitung des QUERY
-Intent zurück.
Befehle an Geräte senden, die mit einem Hub verbunden sind
Wenn du Endgeräte steuern möchtest, die sich hinter einem Hub befinden, musst du möglicherweise zusätzliche Informationen in der protokollspezifischen Befehlspayload 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 device.id
-Wert abgeleitet werden. Wenn dies nicht der Fall ist, sollten Sie diese zusätzlichen Daten in das Feld customData
aufnehmen.
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. Prüfen Sie, ob Ihr Ziel vom Chrome-Browser unterstützt wird.