Per supportare la distribuzione locale, devi creare un'app per gestire questi intent per la smart home:
IDENTIFY
: supporta il rilevamento di smart device controllabili a livello locale. Il gestore di intent estrae i dati restituiti dallo smart device durante il rilevamento e li invia in risposta a Google.EXECUTE
: supporta l'esecuzione di comandi.QUERY
: supporta l'esecuzione di query sullo stato del dispositivo.REACHABLE_DEVICES
: (facoltativo) supporta il rilevamento di dispositivi finali controllabili a livello locale dietro un dispositivo hub (o bridge).
Questa app viene eseguita sui dispositivi Google Home o Google Nest dell'utente e connette il tuo smart device all'assistente. Puoi creare l'app utilizzando TypeScript (opzione preferita) o JavaScript.
TypeScript è consigliato perché puoi utilizzare le associazioni per garantire in modo statico che i dati restituiti dall'app corrispondano ai tipi previsti dalla piattaforma.
Per maggiori dettagli sull'API, consulta il riferimento sull'API Local Home SDK.
Gli snippet seguenti mostrano come inizializzare l'app di fulfillment locale e allegare i gestori.
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"); });
Creazione di un progetto
Per eseguire il deployment dell'app di fulfillment locale, devi creare un bundle JavaScript per il codice e tutte le sue dipendenze.
Utilizza l'inizializzazione di progetto dell'app di fulfillment locale per eseguire il bootstrap della struttura di progetto appropriata con la configurazione del bundler che preferisci.
Modelli di progetto
Per selezionare la configurazione del bundler, esegui il comando npm init
come mostrato negli esempi seguenti:
TypeScript senza configurazione bundler:
npm init @google/local-home-app project-directory/ --bundler none
Struttura del progetto:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
Sostituisci project-directory con una nuova directory che conterrà il progetto dell'app di fulfillment locale.
TypeScript con configurazione bundler webpack:
npm init @google/local-home-app project-directory/ --bundler webpack
Struttura del progetto:
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
Sostituisci project-directory con una nuova directory che conterrà il progetto dell'app di fulfillment locale.
TypeScript con configurazione del bundler Rollup:
npm init @google/local-home-app project-directory/ --bundler rollup
Struttura del progetto:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── rollup.config.js └── serve.js
Sostituisci project-directory con una nuova directory che conterrà il progetto dell'app di fulfillment locale.
TypeScript con configurazione del bundler Parcel:
npm init @google/local-home-app project-directory/ --bundler parcel
Struttura del progetto:
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
Sostituisci project-directory con una nuova directory che conterrà il progetto dell'app di fulfillment locale.
Eseguire attività comuni a livello di progetto
Il progetto generato supporta i seguenti script npm:
cd project-directory/ npm run build
Questo script compila l'origine TypeScript e raggruppa la tua app con le sue dipendenze per l'ambiente di runtime di Chrome nella sottodirectory dist/web
e l'ambiente di runtime Node.js nella sottodirectory dist/node
.
cd project-directory/ npm run lint npm run compile npm test
Questo script verifica la sintassi del codice TypeScript, la compila senza produrre alcun output nella sottodirectory dist/
ed esegue test automatici da test.ts
.
cd project-directory/ npm run start
Durante lo sviluppo, questo script pubblica localmente gli app bundle per gli ambienti di runtime Chrome e Node.js.
Implementa il gestore IDENTIFY
Il gestore IDENTIFY
viene attivato al riavvio del dispositivo Google Home o Google Nest e alla visualizzazione di dispositivi locali non verificati (inclusi i dispositivi finali collegati a un hub). La piattaforma Local Home cercherà dispositivi locali utilizzando le informazioni di configurazione della scansione specificate in precedenza e chiamerà il tuo gestore IDENTIFY
con i risultati della scansione.
Il componente IdentifyRequest
della piattaforma Local Home contiene i dati di scansione di un'istanza LocalIdentifiedDevice
. Viene completata una sola istanza device
in base alla configurazione di scansione che ha rilevato il dispositivo.
Se i risultati della scansione corrispondono al tuo dispositivo, il gestore IDENTIFY
deve restituire un oggetto IdentifyResponsePayload
, che include un oggetto device
con metadati per la smart home (come tipi, trait e stato del report).
Google stabilisce un'associazione del dispositivo se
il valore verificationId
della risposta IDENTIFY
corrisponde a uno dei
valori otherDeviceIds
restituiti dalla risposta SYNC
.
Esempio
Gli snippet seguenti mostrano come creare gestori IDENTIFY
rispettivamente per le integrazioni di dispositivi autonomi e di 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 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; };
Identifica i dispositivi dietro un hub
Se Google identifica un dispositivo hub, considera l'hub come un condotto per i dispositivi finali connessi dell'hub e tenta di verificare questi dispositivi finali.
Per consentire a Google di verificare che sia presente un dispositivo hub, segui queste istruzioni per il tuo gestore IDENTIFY
:
- Se la risposta
SYNC
riporta gli ID dei dispositivi finali locali connessi all'hub, impostaisProxy
cometrue
inIdentifyResponsePayload
. - Se la tua risposta
SYNC
non segnala il tuo dispositivo hub, impostaisLocalOnly
cometrue
inIdentifyResponsePayload
. - Il campo
device.id
contiene l'ID locale del dispositivo hub stesso.
Implementa il gestore REACHABLE_DISPOSITIVI (solo integrazioni hub)
L'intent REACHABLE_DEVICES
viene inviato da Google per confermare quali dispositivi finali
possono essere controllati localmente. Questo intent si attiva ogni volta che Google esegue una scansione di rilevamento (circa una volta al minuto), a condizione che l'hub sia online.
Il gestore REACHABLE_DEVICES
viene implementato in modo simile al gestore IDENTIFY
, ma il gestore deve raccogliere ID dispositivo aggiuntivi raggiungibili dal dispositivo proxy locale (ossia il dispositivo hub). Il campo device.verificationId
contiene l'ID dispositivo locale di un dispositivo finale connesso all'hub.
Il componente ReachableDevicesRequest
della piattaforma Local Home contiene un'istanza di LocalIdentifiedDevice
.
Tramite questa istanza, puoi ottenere l'ID dispositivo proxy e i dati dai risultati della scansione.
Il gestore REACHABLE_DEVICES
deve restituire un oggetto ReachableDevicesPayload
che includa un oggetto devices
contenente un array di valori verificationId
che rappresentano i dispositivi finali controllati dall'hub. I valori verificationId
devono corrispondere a uno dei otherDeviceIds
della risposta SYNC
.
Lo snippet seguente mostra come creare il gestore REACHABLE_DEVICES
.
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; };
Implementa il gestore EXECUTE
Il gestore EXECUTE
nell'app elabora i comandi degli utenti e utilizza
l'SDK Local Home per accedere ai tuoi smart device tramite un protocollo esistente.
La piattaforma Home locale passa al tuo Cloud fulfillment lo stesso payload di input
per la funzione di gestore EXECUTE
dell'intent EXECUTE
. Allo stesso modo, il gestore EXECUTE
restituisce
i dati di output nello stesso formato dell'elaborazione dell'intent EXECUTE
.
Per semplificare la creazione delle risposte, puoi utilizzare la classe Execute.Response.Builder
fornita dall'SDK Local Home.
La tua app non ha accesso diretto all'indirizzo IP del dispositivo. Utilizza invece l'interfaccia CommandRequest
per creare comandi basati su uno dei seguenti protocolli: UDP, TCP o HTTP. Quindi, chiama la funzione
deviceManager.send()
per inviare i comandi.
Quando scegli come target dei comandi ai dispositivi, utilizza l'ID dispositivo (e i parametri del campo customData
, se incluso) della risposta SYNC
per comunicare con il dispositivo.
Esempio
Il seguente snippet di codice mostra come creare il gestore EXECUTE
.
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()); };
Implementa il gestore QUERY
Il tuo gestore QUERY
nell'app elabora le richieste degli utenti e utilizza
l'SDK Local Home per segnalare lo stato dei tuoi smart device.
La piattaforma Local Home passa al tuo Cloud fulfillment lo stesso payload di richieste per la funzione di gestore "QUERY" dell'intent QUERY
. Allo stesso modo, il gestore QUERY
restituisce i dati nello stesso formato dell'elaborazione dell'intent QUERY
.
Invio di comandi a dispositivi dietro un hub
Per controllare i dispositivi finali dietro un hub, potresti dover fornire informazioni aggiuntive nel payload del comando specifico per protocollo inviato all'hub affinché l'hub possa identificare il dispositivo a cui è destinato il comando. In alcuni casi, questo può essere
dedotto direttamente dal valore device.id
, ma se non è così,
devi includere questi dati aggiuntivi nel campo customData
.
Se hai creato l'app utilizzando TypeScript, ricorda di compilare l'app in JavaScript. Per scrivere il codice, puoi utilizzare il sistema di moduli che preferisci. Assicurati che il target sia supportato dal browser Chrome.