Per supportare l'evasione degli ordini locali, devi creare un'app per gestire questi intent per la smart home:
IDENTIFY
: supporta il rilevamento di smart device controllabili localmente. Il gestore degli intent estrae i dati restituiti dallo smart device durante il rilevamento e li invia come risposta a Google.EXECUTE
: supporta l'esecuzione dei comandi.QUERY
: supporta la query sullo stato del dispositivo.REACHABLE_DEVICES
: (Facoltativo) supporta il rilevamento di dispositivi finali controllabili localmente dietro un dispositivo 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 le associazioni per assicurarti in modo statico che i dati restituiti dalla tua app corrispondano ai tipi previsti dalla piattaforma.
Per ulteriori dettagli sull'API, consulta il riferimento all'API Local Home SDK.
Gli snippet riportati di seguito mostrano come inizializzare l'app di evasione degli ordini locale e collegare 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 evasione degli ordini locale, devi creare un bundle JavaScript per il codice e tutte le relative dipendenze.
Utilizza l'inizializzatore del progetto dell'app di evasione degli ordini 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 evasione degli ordini locale.
TypeScript con configurazione del bundling di 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 evasione degli ordini locale.
TypeScript con configurazione del compilatore del bundle 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 evasione degli ordini locale.
TypeScript con configurazione del compilatore del bundle 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 evasione degli ordini locale.
Eseguire attività comuni a livello di progetto
Il progetto generato supporta i seguenti comandi npm:
cd project-directory/ npm run build
Questo script compila il codice sorgente TypeScript e raggruppa l'app con le relative 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 output nella sottodirectory dist/
ed esegue i test automatici da test.ts
.
cd project-directory/ npm run start
Durante lo sviluppo, questo script pubblica localmente i bundle dell'app per gli ambienti di runtime di Chrome e Node.js.
Implementare il gestore IDENTIFY
L'handler IDENTIFY
viene attivato quando il dispositivo Google Home o Google Nest si riavvia e rileva dispositivi locali non verificati (inclusi i dispositivi finali collegati a un hub). La piattaforma Local Home cercherà i dispositivi locali utilizzando le informazioni sulla configurazione della scansione che hai specificato in precedenza e chiamerà il tuo gestore IDENTIFY
con i risultati della scansione.
Il
IdentifyRequest
della piattaforma Local Home contiene i dati di scansione di un'istanza
LocalIdentifiedDevice
. Viene compilata una sola istanza device
, in base alla configurazione della scansione che ha rilevato il dispositivo.
Se i risultati della ricerca corrispondono al tuo dispositivo, l'handler IDENTIFY
deve restituire un oggetto
IdentifyResponsePayload
che include un oggetto device
con
metadati per la smart home (ad esempio tipi, tratti 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 riportati di seguito mostrano come creare gestori IDENTIFY
per le integrazioni di hub e dispositivi autonomi, rispettivamente.
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; };
Identificare i dispositivi dietro un hub
Se Google identifica un hub, lo tratterà come il canale di accesso ai dispositivi di destinazione connessi e tenterà di verificarli.
Per consentire a Google di verificare la presenza di un hub, segui queste istruzioni per il tuo IDENTIFY
handler:
- Se la risposta
SYNC
riporta gli ID dei dispositivi finali locali connessi all'hub, impostaisProxy
sutrue
inIdentifyResponsePayload
. - Se la risposta
SYNC
non segnala il dispositivo hub, impostaisLocalOnly
sutrue
inIdentifyResponsePayload
. - Il campo
device.id
contiene l'ID dispositivo locale del dispositivo hub stesso.
Implementare il gestore REACHABLE_DEVICES (solo integrazioni hub)
L'intent REACHABLE_DEVICES
viene inviato da Google per confermare quali dispositivi finali possono essere controllati localmente. Questo intento viene attivato ogni volta che Google esegue una scansione di scoperta (circa una volta ogni minuto), a condizione che l'hub sia rilevato come online.
L'handler REACHABLE_DEVICES
viene implementato in modo simile all'handler IDENTIFY
, tranne per il fatto che 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
collegato all'hub.
Il
ReachableDevicesRequest
della piattaforma Local Home contiene un'istanza di
LocalIdentifiedDevice
.
Tramite questa istanza, puoi ottenere l'ID dispositivo proxy e i dati provenienti dai risultati della scansione.
L'handler 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 valori otherDeviceIds
della risposta SYNC
.
Lo snippet seguente mostra come creare l'handler 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
L'handler EXECUTE
nell'app elabora i comandi degli utenti e utilizza l'SDK Local Home per accedere agli smart device tramite un protocollo esistente.
La piattaforma Local Home passa lo stesso payload di input alla funzione di gestore EXECUTE
come per l'intent EXECUTE
al tuo cloud fulfillment. Analogamente, l'handler 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 scegli come target i comandi per i 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 l'handler 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()); };
Implementare l'handler QUERY
L'handler 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 lo stesso payload della richiesta alla funzione di gestore "QUERY" come per lo scopo QUERY
al tuo cloud fulfillment. Analogamente, l'handler QUERY
restituisce i dati nello stesso formato dell'elaborazione dell'intent QUERY
.
Invio di comandi ai dispositivi dietro un hub
Per controllare i dispositivi di destinazione dietro un hub, potresti dover fornire informazioni aggiuntive nel payload del comando specifico del protocollo inviato all'hub affinché quest'ultimo possa identificare il dispositivo a cui è rivolto il comando. In alcuni casi, questo valore può essere ricavato direttamente dal valore device.id
, ma in caso contrario, 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 la destinazione sia supportata dal browser Chrome.