Zur Unterstützung der lokalen Auftragsausführung musst du eine App erstellen, die diese Smart-Home-Intents verarbeitet:
IDENTIFY
: Unterstützt die Erkennung lokal steuerbarer Smart-Home-Geräte. Der Intent-Handler extrahiert Daten, die Ihr Smart-Home-Gerät während der Erkennung zurückgibt, und sendet sie 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 lokal steuerbarer Endgeräte 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 dein Smart-Home-Gerät mit Assistant. Sie können die App 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 den Typen entsprechen, die von der Plattform erwartet werden.
Weitere Informationen zur API findest du in der Referenz zur Local Home SDK API.
Die folgenden Snippets zeigen, wie Sie die lokale Auftragsausführungs-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 Auftragsausführungs-App bereitstellen können, müssen Sie ein JavaScript-Bundle für den Code und alle zugehörigen Abhängigkeiten erstellen.
Verwenden Sie den Projektinitialisierer der Anwendung für die Auftragsausführung, um die entsprechende Projektstruktur mit Ihrer bevorzugten Bundler-Konfiguration zu starten.
Projektvorlagen
Führen Sie zum Auswählen der Bundler-Konfiguration den Befehl npm init
aus, 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 lokalen Auftragsausführungs-App enthalten wird.
TypeScript mit der 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 lokalen Auftragsausführungs-App enthalten wird.
TypeScript mit der 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 lokalen Auftragsausführungs-App enthalten wird.
TypeScript mit der 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 lokalen Auftragsausführungs-App enthalten wird.
Gängige Aufgaben auf Projektebene ausführen
Das generierte Projekt unterstützt die folgenden npm-Skripts:
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
.
cd project-directory/ npm run lint npm run compile npm test
Dieses Skript überprüft die Syntax Ihres TypeScript-Codes, kompiliert ihn, ohne dass im Unterverzeichnis dist/
ausgegeben wird, und führt automatisierte Tests über test.ts
aus.
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 gestartet wird und nicht bestätigte lokale Geräte erkannt werden, einschließlich Endgeräten, die mit einem Hub verbunden sind. Die Local Home-Plattform sucht anhand der zuvor angegebenen Scankonfigurationsinformationen nach lokalen Geräten und ruft den IDENTIFY
-Handler mit den Scanergebnissen auf.
Der IdentifyRequest
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 mit Ihrem Gerät übereinstimmen, sollte der IDENTIFY
-Handler ein IdentifyResponsePayload
-Objekt zurückgeben, das ein device
-Objekt mit Smart-Home-Metadaten (z. B. Typen, Merkmale und Berichtsstatus) enthält.
Google richtet eine Geräteverknüpfung ein, wenn 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.
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 erkennen
Wenn Google ein Hub-Gerät identifiziert, wird der Hub als Conduit zu den mit dem Hub verbundenen Endgeräten behandelt und versucht, diese Endgeräte zu verifizieren.
Damit Google bestätigen kann, dass ein Hub-Gerät vorhanden ist, folgen Sie dieser Anleitung für Ihren IDENTIFY
-Handler:
- Wenn Ihre
SYNC
-Antwort die IDs der lokalen Endgeräte enthält, die mit dem Hub verbunden sind, legen SieisProxy
inIdentifyResponsePayload
auftrue
fest. - Wenn Ihr Hub-Gerät in der
SYNC
-Antwort nicht gemeldet wird, legen SieisLocalOnly
inIdentifyResponsePayload
alstrue
fest. - Das Feld
device.id
enthält die lokale Geräte-ID für das Hub-Gerät selbst.
REACHABLE_GERÄTE-Handler implementieren (nur Hub-Integrationen)
Der Intent REACHABLE_DEVICES
wird von Google gesendet, um zu prüfen, 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), sofern erkannt wird, dass der Hub online ist.
Der Handler REACHABLE_DEVICES
wird ähnlich wie der Handler IDENTIFY
implementiert, mit der Ausnahme, dass er zusätzliche Geräte-IDs erfassen muss, die über das lokale Proxygerät (das Hub-Gerät) erreichbar sind. Das Feld device.verificationId
enthält die lokale Geräte-ID für ein Endgerät, das mit dem Hub verbunden ist.
Der ReachableDevicesRequest
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
aus der SYNC
-Antwort übereinstimmen.
Das folgende Snippet zeigt, wie Sie den 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 deine Smart-Home-Geräte zuzugreifen.
Die Local Home-Plattform übergibt die gleiche Eingabenutzlast an die Handler-Funktion EXECUTE
wie für den EXECUTE
-Intent an die Cloud-Auftragsausführung. Ebenso gibt der EXECUTE
-Handler die Ausgabedaten im selben Format wie bei der Verarbeitung des Intents EXECUTE
zurück.
Mit der Klasse Execute.Response.Builder
des Local Home SDK lässt sich das Erstellen von Antworten vereinfachen.
Ihre App hat keinen direkten Zugriff auf die IP-Adresse des Geräts. Verwenden Sie stattdessen die Schnittstelle CommandRequest
, um Befehle auf der Grundlage eines dieser 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 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 den 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
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-Plattform übergibt die gleiche Nutzlast der Anfrage an die Handler-Funktion „QUERY“ wie für den Intent QUERY
an die Cloud-Auftragsausführung. Analog dazu gibt der QUERY
-Handler Daten in demselben Format zurück, in dem sie auch beim QUERY
-Intent verarbeitet wurden.
Befehle an Geräte hinter einem Hub senden
Zum Steuern von Endgeräten hinter einem Hub 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 App mit TypeScript erstellt haben, müssen Sie sie auch mit JavaScript kompilieren. Zum Schreiben des Codes können Sie das Modulsystem Ihrer Wahl verwenden. Prüfen Sie, ob das Ziel vom Chrome-Browser unterstützt wird.