Per supportare l'evasione locale, devi creare un'app per gestire questi intent di smart home:
IDENTIFY: supporta il rilevamento di smart device controllabili localmente. Il gestore di intent estrae i dati restituiti dallo smart device durante il discovery e li invia in una 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 localmente dietro un hub (o bridge).
Questa app viene eseguita sui dispositivi Google Home o Google Nest dell'utente e connette lo smart device all'assistente. Puoi creare l'app utilizzando TypeScript (opzione preferita) o JavaScript.
TypeScript è consigliato perché puoi sfruttare i binding per garantire staticamente che i dati restituiti dalla tua app corrispondano ai tipi previsti dalla piattaforma.
Per maggiori dettagli sull'API, consulta il Riferimento API Local Home SDK.
I seguenti snippet mostrano come inizializzare l'app di fulfillment locale e collegare i tuoi 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 tuo codice e tutte le relative dipendenze.
Utilizza l'inizializzatore del progetto dell'app di fulfillment locale per avviare la struttura del 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 del 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.
Configurazione del bundler webpack con TypeScript:
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.
Configurazione del bundler TypeScript con 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.
Esegui attività comuni a livello di progetto
Il progetto generato supporta i seguenti script npm:
cd project-directory/ npm run build
Questo script compila il codice sorgente TypeScript e raggruppa la tua app con le sue dipendenze per l'ambiente di runtime di Chrome nella sottodirectory dist/web e per l'ambiente di runtime di 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, lo 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 gestisce i bundle dell'app per gli ambienti di runtime di Chrome e Node.js in locale.
Implementa il gestore IDENTIFY
Il gestore IDENTIFY verrà attivato quando il dispositivo Google Home o Google Nest si riavvia e
rileva dispositivi locali non verificati (inclusi i dispositivi finali connessi a un hub). La piattaforma Local Home cercherà i dispositivi locali utilizzando le informazioni di configurazione della scansione specificate in precedenza e chiamerà il gestore IDENTIFY con i risultati della scansione.
IdentifyRequest
della piattaforma Local Home contiene i dati di scansione di un'istanza
LocalIdentifiedDevice. Viene compilata 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 della smart home (come tipi, tratti e stato del report).
Google stabilisce un'associazione del dispositivo se
il verificationId della risposta IDENTIFY corrisponde a uno dei
valori otherDeviceIds restituiti dalla risposta SYNC.
Esempio
I seguenti snippet mostrano come creare gestori IDENTIFY per le integrazioni di dispositivi e hub autonomi.
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 hub, lo considererà come il canale di comunicazione con i dispositivi finali connessi all'hub e tenterà di verificare questi dispositivi finali.
Per consentire a Google di confermare la presenza di un dispositivo hub, segui queste istruzioni per il tuo gestore IDENTIFY:
- Se la risposta
SYNCsegnala gli ID dei dispositivi finali locali connessi all'hub, impostaisProxysutrueinIdentifyResponsePayload. - Se la risposta
SYNCnon segnala il tuo dispositivo hub, impostaisLocalOnlysutrueinIdentifyResponsePayload. - Il campo
device.idcontiene l'ID dispositivo locale del dispositivo hub stesso.
Implementa il gestore REACHABLE_DEVICES (solo integrazioni con hub)
L'intent REACHABLE_DEVICES viene inviato da Google per confermare quali dispositivi finali possono essere controllati localmente. Questo intent viene attivato ogni volta che Google esegue una scansione di rilevamento (circa una volta al minuto), purché l'hub venga rilevato come online.
Il gestore REACHABLE_DEVICES viene implementato in modo simile al gestore IDENTIFY, con la differenza che il gestore deve raccogliere ID dispositivo aggiuntivi raggiungibili dal dispositivo proxy locale (ovvero l'hub). Il campo device.verificationId contiene l'ID dispositivo locale di un dispositivo finale connesso all'hub.
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 include 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.
Il seguente snippet 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 dell'utente e utilizza l'SDK Local Home per accedere agli smart device tramite un protocollo esistente.
La piattaforma Local Home trasmette alla funzione del gestore EXECUTE lo stesso payload di input dell'intent EXECUTE al tuo fulfillment in cloud. Analogamente, il gestore EXECUTE restituisce i dati di output nello stesso formato dell'elaborazione dell'intent EXECUTE.
Per semplificare la creazione della risposta, 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 di questi protocolli: UDP, TCP o HTTP. Quindi, chiama la funzione deviceManager.send() per inviare i comandi.
Quando indirizzi i comandi ai dispositivi, utilizza l'ID dispositivo (e i parametri del campo customData, se inclusi) 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 gestore QUERY nell'app elabora le richieste degli utenti e utilizza l'SDK Local Home per segnalare lo stato degli smart device.
La piattaforma Local Home trasmette alla funzione del gestore "QUERY" lo stesso payload della richiesta dell'intent QUERY al tuo fulfillment in cloud. Analogamente, il gestore QUERY restituisce i dati nello stesso formato dell'elaborazione dell'intent QUERY.
Invio di comandi ai dispositivi dietro un hub
Per controllare i dispositivi finali dietro un hub, potrebbe essere necessario fornire informazioni aggiuntive
nel payload del comando specifico del protocollo inviato all'hub, in modo che l'hub
possa identificare il dispositivo a cui è destinato il comando. In alcuni casi, questo può essere dedotto direttamente dal valore device.id, ma quando non è così, devi includere questi dati aggiuntivi nel campo customData.
Se hai creato l'app utilizzando TypeScript, ricordati di compilarla in JavaScript. Puoi utilizzare il sistema di moduli che preferisci per scrivere il codice. Assicurati che il target sia supportato dal browser Chrome.