Migliora e proteggi le tue azioni per la smart home

1. Prima di iniziare

Le azioni della smart home utilizzano i tipi di dispositivi per comunicare all'Assistente Google quale grammatica utilizzare con un dispositivo. I trait dei dispositivi definiscono le funzionalità di un tipo di dispositivo. Un dispositivo eredita gli stati di ogni trait del dispositivo aggiunto a un'Azione.

dc8dce0dea87cd5c.png

Puoi collegare qualsiasi trait supportato al tipo di dispositivo scelto per personalizzare la funzionalità dei dispositivi degli utenti. Se vuoi implementare nelle tue azioni tratti personalizzati che non sono attualmente disponibili nello schema del dispositivo, i trait Modalità e Attivazioni consentono un controllo delle impostazioni specifiche con un nome personalizzato definito da te.

Oltre alla funzionalità di controllo di base fornita dai tipi e dai trait, l'API Smart Home offre funzionalità aggiuntive per migliorare l'esperienza utente. Quando gli intent non hanno esito positivo, le risposte di errore forniscono un feedback dettagliato sugli utenti. La verifica utente secondaria estende queste risposte e rafforza la sicurezza del tratto dispositivo che scegli. Inviando risposte di errore specifiche ai blocchi di verifica emessi dall'Assistente, l'Azione per la smart home può richiedere un'autorizzazione aggiuntiva per completare un comando.

Prerequisiti

Cosa creerai

In questo codelab, eseguirai il deployment di un'integrazione predefinita della smart home con Firebase, quindi imparerai ad aggiungere tratti non standard alla lavaggio smart home per dimensioni di carico e modalità turbo. Implementerai anche la segnalazione di errori ed eccezioni e imparerai a imporre una conferma verbale per accendere la lavatrice utilizzando la verifica utente secondaria.

Cosa imparerai a fare

  • Come aggiungere i tratti delle modalità e dei pulsanti di attivazione/disattivazione all'azione
  • Come segnalare errori ed eccezioni
  • Come applicare la verifica utente secondaria

Che cosa ti serve

2. Per iniziare

Attivare la Gestione attività

Per utilizzare l'Assistente Google, devi condividere con Google determinati dati relativi alle attività. L'Assistente Google ha bisogno di questi dati per funzionare correttamente; tuttavia, il requisito di condivisione dei dati non è specifico dell'SDK. Per condividere questi dati, crea un Account Google se non ne hai già uno. Puoi utilizzare qualsiasi Account Google, non è necessario che sia il tuo account sviluppatore.

Apri la pagina Gestione attività relativa all'Account Google che vuoi usare con l'assistente.

Assicurati che le seguenti opzioni di attivazione/disattivazione siano abilitate:

  • Attività web e app: assicurati di selezionare la casella di controllo Includi la cronologia di Chrome e le attività svolte su siti, app e dispositivi che usano i servizi Google.
  • Informazioni del dispositivo
  • Attività vocale e audio

Creare un progetto Actions

  1. Vai alla Play Console per gli sviluppatori di Actions on Google.
  2. Fai clic su Nuovo progetto, inserisci un nome per il progetto e fai clic su CREA PROGETTO.

3d6b68ca79afd54c.png

Seleziona l'app Smart home

Nella schermata Panoramica della console Actions, seleziona Smart home.

2fa4988f44f8914b.png

Scegli la scheda dell'esperienza Smart home, fai clic su Inizia a costruire e si aprirà la console del tuo progetto.

Installa l'interfaccia a riga di comando di Firebase

L'interfaccia a riga di comando (CLI) di Firebase ti consente di pubblicare le tue app web localmente ed eseguire il deployment dell'app web su Firebase Host.

Per installare l'interfaccia a riga di comando, esegui questo comando npm dal terminale:

npm install -g firebase-tools

Per verificare che l'interfaccia a riga di comando sia stata installata correttamente, esegui:

firebase --version

Autorizza l'interfaccia a riga di comando di Firebase con il tuo Account Google eseguendo:

firebase login

Abilita l'API HomeGraph

L'API HomeGraph consente l'archiviazione e l'esecuzione di query sui dispositivi e sui loro stati all'interno di Home Graph di un utente. Per utilizzare questa API, devi prima aprire la console Google Cloud e abilitare l'API HomeGraph.

Nella console Google Cloud, assicurati di selezionare il progetto che corrisponde alle tue azioni <project-id>.. Quindi, nella schermata della libreria API per l'API HomeGraph, fai clic su Abilita.

ee198858a6eac112.png

3. Esegui l'app di base

Ora che hai configurato l'ambiente di sviluppo, puoi eseguire il deployment del progetto iniziale per verificare che tutto sia configurato correttamente.

Ottieni il codice sorgente

Fai clic sul seguente link per scaricare l'esempio per questo codelab sulla tua macchina di sviluppo:

...oppure clona il repository GitHub dalla riga di comando:

git clone https://github.com/google-home/smarthome-traits.git

Decomprimi il file ZIP scaricato.

Informazioni sul progetto

Il progetto iniziale contiene le seguenti sottodirectory:

  • public: Un'interfaccia utente frontend per controllare e monitorare facilmente lo stato della lavatrice smart.
  • functions: Un servizio cloud completamente implementato che gestisce la smartwash con Cloud Functions for Firebase e Firebase Realtime Database.

Il fulfillment Cloud fornito include le seguenti funzioni in index.js:

  • fakeauth: endpoint di autorizzazione per il collegamento dell'account
  • faketoken: endpoint token per il collegamento dell'account
  • smarthome: endpoint di fulfillment dell'intent per la smart home
  • reportstate: richiama l'API Home Graph in caso di modifiche dello stato del dispositivo
  • requestsync: abilita gli aggiornamenti dei dispositivi degli utenti senza dover ricollegare l'account

Connettersi a Firebase

Vai alla directory washer-start, quindi configura l'interfaccia a riga di comando di Firebase con il tuo progetto Actions:

cd washer-start
firebase use <project-id>

Configura progetto Firebase

Inizializzare un progetto Firebase.

firebase init

Seleziona le funzionalità dell'interfaccia a riga di comando, Realtime Database, Funzioni e la funzionalità Hosting che include Firebase Hosting.

? Which Firebase CLI features do you want to set up for this directory? Press Space to select features, then
 Enter to confirm your choices.
❯◉ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance
 ◯ Firestore: Configure security rules and indexes files for Firestore
 ◉ Functions: Configure a Cloud Functions directory and its files
 ◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys
 ◯ Hosting: Set up GitHub Action deploys
 ◯ Storage: Configure a security rules file for Cloud Storage
 ◯ Emulators: Set up local emulators for Firebase products
 ◯ Remote Config: Configure a template file for Remote Config
 ◯ Extensions: Set up an empty Extensions manifest

Questa operazione inizializza le API e le funzionalità necessarie per il tuo progetto.

Quando richiesto, inizializza Realtime Database. Puoi utilizzare la località predefinita per l'istanza di database.

? It seems like you haven't initialized Realtime Database in your project yet. Do you want to set it up?
Yes

? Please choose the location for your default Realtime Database instance:
us-central1

Poiché utilizzi il codice del progetto iniziale, scegli il file predefinito per le regole di sicurezza e assicurati di non sovrascrivere il file delle regole del database esistente.

? File database.rules.json already exists. Do you want to overwrite it with the Realtime Database Security Rules for <project-ID>-default-rtdb from the Firebase Console?
No

Se stai reinizializzando il progetto, seleziona Sovrascrivi quando ti viene chiesto se vuoi inizializzare o sovrascrivere un codebase.

? Would you like to initialize a new codebase, or overwrite an existing one?
Overwrite

Quando configuri le funzioni, devi utilizzare i file predefiniti e assicurarti di non sovrascrivere i file index.js e package.json esistenti nell'esempio del progetto.

? What language would you like to use to write Cloud Functions?
JavaScript

? Do you want to use ESLint to catch probable bugs and enforce style?
No

? File functions/package.json already exists. Overwrite?
No

? File functions/index.js already exists. Overwrite?
No

Se stai reinizializzando il progetto, seleziona No quando ti viene chiesto se vuoi inizializzare o sovrascrivere Functions/.gitignore.

? File functions/.gitignore already exists. Overwrite?
No
? Do you want to install dependencies with npm now?
Yes

Infine, configura la configurazione di Hosting in modo che utilizzi la directory public nel codice del progetto e il file index.html esistente. Seleziona No quando ti viene chiesto di utilizzare ESLint.

? What do you want to use as your public directory?
public

? Configure as a single-page app (rewrite all urls to /index.html)?
Yes

? Set up automatic builds and deploys with GitHub?
No

? File public/index.html already exists. Overwrite?
 No

Se ESLint è stato attivato per errore, esistono due metodi per disabilitarlo:

  1. Utilizzando la GUI, vai alla cartella ../functions del progetto, seleziona il file nascosto .eslintrc.js ed eliminalo. Non scambiarlo con il nome simile .eslintrc.json.
  2. Utilizzo della riga di comando:
    cd functions
    rm .eslintrc.js
    

Eseguire il deployment in Firebase

Ora che hai installato le dipendenze e configurato il progetto, puoi eseguire l'app per la prima volta.

firebase deploy

Questo è l'output della console che dovresti vedere:

...

✔ Deploy complete!

Project Console: https://console.firebase.google.com/project/<project-id>/overview
Hosting URL: https://<project-id>.web.app

Questo comando esegue il deployment di un'app web e di diverse Cloud Functions for Firebase.

Apri l'URL di hosting nel tuo browser (https://<project-id>.web.app) per visualizzare l'app web. Vedrai l'interfaccia seguente:

5845443e94705557.png

Questa UI web rappresenta una piattaforma di terze parti per visualizzare o modificare gli stati dei dispositivi. Per iniziare a completare il database con le informazioni del dispositivo, fai clic su AGGIORNA. Non vedrai alcuna modifica sulla pagina, ma lo stato attuale della lavatrice verrà memorizzato nel database.

Ora è il momento di connettere il servizio cloud di cui hai eseguito il deployment all'Assistente Google utilizzando la console di Actions.

Configura il progetto della console Actions

In Panoramica > Crea la tua azione, seleziona Aggiungi azioni. Inserisci l'URL della funzione Cloud Functions che fornisce il fulfillment per gli intent della smart home e fai clic su Salva.

https://us-central1-<project-id>.cloudfunctions.net/smarthome

9d7b223427f587ca.png

Nella scheda Sviluppa > Chiamata, aggiungi un Nome visualizzato per l'azione e fai clic su Salva. Questo nome verrà visualizzato nell'app Google Home.

774d0c40c351c7da.png

a8c4673eb11d76ee.png

Per attivare il collegamento degli account, seleziona l'opzione Sviluppo > Collegamento dell'account nel pannello di navigazione a sinistra. Utilizza queste impostazioni di collegamento dell'account:

ID client

ABC123

Client secret

DEF456

URL autorizzazione

https://us-central1-<project-id>.cloudfunctions.net/fakeauth

URL token

https://us-central1-<project-id>.cloudfunctions.net/faketoken

9730d20b90bcc038.png

Fai clic su Salva per salvare la configurazione del collegamento dell'account e poi su Test per attivare i test sul progetto.

ee0547f05b5efd98.png

Verrà eseguito il reindirizzamento al Simulatore. Se non vedi "Test ora abilitato", fai clic su Reimposta test per verificare che i test siano attivati.

d0495810dbadf059.png

Per testare l'Azione per la smart home, devi collegare il tuo progetto a un Account Google. In questo modo è possibile eseguire test tramite le piattaforme dell'Assistente Google e l'app Google Home su cui è stato eseguito l'accesso allo stesso account.

  1. Sullo smartphone, apri le impostazioni dell'Assistente Google. Tieni presente che devi aver eseguito l'accesso con lo stesso account utilizzato nella console.
  2. Vai a Assistente Google > Impostazioni > Controllo della casa (sotto Assistente).
  3. Fai clic sull'icona di ricerca in alto a destra.
  4. Cerca l'app di test utilizzando il prefisso [test] per trovare l'app di test specifica.
  5. Seleziona l'elemento. L'Assistente Google eseguirà quindi l'autenticazione con il tuo servizio e invierà una richiesta SYNC, chiedendo al servizio di fornire un elenco di dispositivi per l'utente.

Apri l'app Google Home e verifica che sia visibile il dispositivo della lavatrice.

ae252220753726f6.png

Verifica di poter controllare la lavatrice utilizzando i comandi vocali nell'app Google Home. Dovresti anche vedere lo stato del dispositivo cambiare nell'interfaccia utente web di frontend del tuo Cloud fulfillment.

Ora che hai implementato una lavatrice di base, puoi personalizzare le modalità disponibili sul tuo dispositivo.

4. Aggiungi modalità

Il trait action.devices.traits.Modes consente a un dispositivo di avere un numero arbitrario di impostazioni per una modalità, di cui è possibile impostare solo una alla volta. Aggiungerai una modalità alla lavatrice per definire le dimensioni del carico del bucato: piccolo, medio o grande.

Aggiorna risposta SYNC

Devi aggiungere informazioni sul nuovo trait alla tua risposta SYNC in functions/index.js. Questi dati vengono visualizzati nell'array traits e nell'oggetto attributes come mostrato nello snippet di codice riportato di seguito.

index.js

app.onSync(body => {
  return {
    requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    payload: {
      agentUserId: USER_ID,
      devices: [{
        id: 'washer',
        type: 'action.devices.types.WASHER',
        traits: [
          'action.devices.traits.OnOff',
          'action.devices.traits.StartStop',
          'action.devices.traits.RunCycle',
          // Add Modes trait
          'action.devices.traits.Modes',
        ],
        name: { ... },
        deviceInfo: { ... },
        attributes: {
          pausable: true,
          //Add availableModes
          availableModes: [{
            name: 'load',
            name_values: [{
              name_synonym: ['load'],
              lang: 'en',
            }],
            settings: [{
              setting_name: 'small',
              setting_values: [{
                setting_synonym: ['small'],
                lang: 'en',
              }]
            }, {
              setting_name: 'medium',
              setting_values: [{
                setting_synonym: ['medium'],
                lang: 'en',
              }]
            }, {
              setting_name: 'large',
              setting_values: [{
                setting_synonym: ['large'],
                lang: 'en',
              }]
            }],
            ordered: true,
          }],
        },
      }],
    },
  };
});

Aggiungi nuovi comandi per intent EXECUTE

Nell'intent EXECUTE, aggiungi il comando action.devices.commands.SetModes come mostrato nello snippet di codice riportato di seguito.

index.js

const updateDevice = async (execution,deviceId) => {
  const {params,command} = execution;
  let state, ref;
  switch (command) {
    case 'action.devices.commands.OnOff':
      state = {on: params.on};
      ref = firebaseRef.child(deviceId).child('OnOff');
      break;
    case 'action.devices.commands.StartStop':
      state = {isRunning: params.start};
      ref = firebaseRef.child(deviceId).child('StartStop');
      break;
    case 'action.devices.commands.PauseUnpause':
      state = {isPaused: params.pause};
      ref = firebaseRef.child(deviceId).child('StartStop');
      Break;
    // Add SetModes command
    case 'action.devices.commands.SetModes':
      state = {load: params.updateModeSettings.load};
      ref = firebaseRef.child(deviceId).child('Modes');
      break;
}

Aggiorna la risposta QUERY

Quindi, aggiorna la risposta QUERY per segnalare lo stato attuale della lavatrice.

Aggiungi le modifiche aggiornate alle funzioni queryFirebase e queryDevice per ottenere lo stato archiviato nel Realtime Database.

index.js

const queryFirebase = async (deviceId) => {
  const snapshot = await firebaseRef.child(deviceId).once('value');
  const snapshotVal = snapshot.val();
  return {
    on: snapshotVal.OnOff.on,
    isPaused: snapshotVal.StartStop.isPaused,
    isRunning: snapshotVal.StartStop.isRunning,
    // Add Modes snapshot
    load: snapshotVal.Modes.load,
  };
}

const queryDevice = async (deviceId) => {
  const data = await queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{ ... }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
    // Add currentModeSettings
    currentModeSettings: {
      load: data.load,
    },
  };
};

Aggiorna stato report

Infine, aggiorna la funzione reportstate per segnalare l'attuale impostazione di carico della lavatrice a Home Graph.

index.js

const requestBody = {
  requestId: 'ff36a3cc', /* Any unique ID */
  agentUserId: USER_ID,
  payload: {
    devices: {
      states: {
        /* Report the current state of your washer */
        [context.params.deviceId]: {
          on: snapshot.OnOff.on,
          isPaused: snapshot.StartStop.isPaused,
          isRunning: snapshot.StartStop.isRunning,
          // Add currentModeSettings
          currentModeSettings: {
            load: snapshot.Modes.load,
          },
        },
      },
    },
  },
};

Eseguire il deployment in Firebase

Esegui questo comando per eseguire il deployment dell'azione aggiornata:

firebase deploy --only functions

Al termine del deployment, vai all'interfaccia utente web e fai clic sul pulsante Aggiorna ae8d3b25777a5e30.png nella barra degli strumenti. Questa operazione attiva una sincronizzazione delle richieste in modo che l'assistente riceva i dati aggiornati della risposta di SYNC.

bf4f6a866160a982.png

Ora puoi dare un comando per impostare la modalità della lavatrice, ad esempio:

"Hey Google, imposta il carico della lavatrice su grande."

Puoi anche fare domande sulla lavatrice, ad esempio:

"Hey Google, qual è il carico della lavatrice?"

5. Aggiungi pulsanti di attivazione/disattivazione

Il trait action.devices.traits.Toggles rappresenta gli aspetti denominati di un dispositivo con uno stato vero o falso, ad esempio se la lavatrice è in modalità turbo.

Aggiorna risposta SYNC

Nella risposta SYNC, devi aggiungere informazioni sul nuovo trait del dispositivo. Verrà visualizzato nell'array traits e nell'oggetto attributes come mostrato nello snippet di codice che segue.

index.js

app.onSync(body => {
  return {
    requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
    payload: {
      agentUserId: USER_ID,
      devices: [{
        id: 'washer',
        type: 'action.devices.types.WASHER',
        traits: [
          'action.devices.traits.OnOff',
          'action.devices.traits.StartStop',
          'action.devices.traits.RunCycle',
          'action.devices.traits.Modes',
          // Add Toggles trait
          'action.devices.traits.Toggles',
        ],
        name: { ... },
        deviceInfo: { ... },
        attributes: {
          pausable: true,
          availableModes: [{
            name: 'load',
            name_values: [{
              name_synonym: ['load'],
              lang: 'en'
            }],
            settings: [{ ... }],
            ordered: true,
          }],
          //Add availableToggles
          availableToggles: [{
            name: 'Turbo',
            name_values: [{
              name_synonym: ['turbo'],
              lang: 'en',
            }],
          }],
        },
      }],
    },
  };
});

Aggiungere nuovi comandi per intent EXECUTE

Nell'intent EXECUTE, aggiungi il comando action.devices.commands.SetToggles come mostrato nello snippet di codice riportato di seguito.

index.js

const updateDevice = async (execution,deviceId) => {
  const {params,command} = execution;
  let state, ref;
  switch (command) {
    case 'action.devices.commands.OnOff':
      state = {on: params.on};
      ref = firebaseRef.child(deviceId).child('OnOff');
      break;
    case 'action.devices.commands.StartStop':
      state = {isRunning: params.start};
      ref = firebaseRef.child(deviceId).child('StartStop');
      break;
    case 'action.devices.commands.PauseUnpause':
      state = {isPaused: params.pause};
      ref = firebaseRef.child(deviceId).child('StartStop');
      break;
    case 'action.devices.commands.SetModes':
      state = {load: params.updateModeSettings.load};
      ref = firebaseRef.child(deviceId).child('Modes');
      break;
    // Add SetToggles command
    case 'action.devices.commands.SetToggles':
      state = {Turbo: params.updateToggleSettings.Turbo};
      ref = firebaseRef.child(deviceId).child('Toggles');
      break;
  }

Aggiorna la risposta QUERY

Infine, devi aggiornare la risposta QUERY per segnalare la modalità turbo della lavatrice. Aggiungi le modifiche aggiornate alle funzioni queryFirebase e queryDevice per ottenere lo stato di attivazione/disattivazione così come archiviato nel Realtime Database.

index.js

const queryFirebase = async (deviceId) => {
  const snapshot = await firebaseRef.child(deviceId).once('value');
  const snapshotVal = snapshot.val();
  return {
    on: snapshotVal.OnOff.on,
    isPaused: snapshotVal.StartStop.isPaused,
    isRunning: snapshotVal.StartStop.isRunning,
    load: snapshotVal.Modes.load,
    // Add Toggles snapshot
    Turbo: snapshotVal.Toggles.Turbo,
  };
}

const queryDevice = async (deviceId) => {
  const data = queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{ ... }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
    currentModeSettings: {
      load: data.load,
    },
    // Add currentToggleSettings
    currentToggleSettings: {
      Turbo: data.Turbo,
    },
  };
};

Aggiorna stato report

Infine, aggiorna la funzione reportstate per segnalare a Home Graph se la lavatrice è impostata su turbo.

index.js

const requestBody = {
  requestId: 'ff36a3cc', /* Any unique ID */
  agentUserId: USER_ID,
  payload: {
    devices: {
      states: {
        /* Report the current state of your washer */
        [context.params.deviceId]: {
          on: snapshot.OnOff.on,
          isPaused: snapshot.StartStop.isPaused,
          isRunning: snapshot.StartStop.isRunning,
          currentModeSettings: {
            load: snapshot.Modes.load,
          },
          // Add currentToggleSettings
          currentToggleSettings: {
            Turbo: snapshot.Toggles.Turbo,
          },
        },
      },
    },
  },
};

Eseguire il deployment in Firebase

Esegui questo comando per eseguire il deployment delle funzioni aggiornate:

firebase deploy --only functions

Fai clic sul pulsante Aggiorna ae8d3b25777a5e30.png nell'interfaccia utente web per attivare una sincronizzazione delle richieste al completamento del deployment.

Ora puoi dare un comando per impostare la modalità turbo della lavatrice dicendo:

"Hey Google, attiva il turbo per la lavatrice."

Puoi anche controllare se la lavatrice è già in modalità turbo chiedendo:

"Hey Google, la lavatrice è in modalità turbo?"

6. Segnalare errori ed eccezioni

La gestione degli errori nell'Azione per la smart home ti consente di segnalare agli utenti quando dei problemi causano la mancata riuscita delle risposte di EXECUTE e QUERY. Le notifiche creano un'esperienza più positiva per i tuoi utenti quando interagiscono con il tuo smart device e l'Azione.

Ogni volta che una richiesta EXECUTE o QUERY non va a buon fine, l'Azione dovrebbe restituire un codice di errore. Se, ad esempio, vuoi generare un errore quando un utente tenta di avviare la lavatrice con il coperchio aperto, la risposta EXECUTE sarà simile al seguente snippet di codice:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [
      {
        "ids": [
          "456"
        ],
        "status": "ERROR",
        "errorCode": "deviceLidOpen"
      }
    ]
  }
}

Ora, quando un utente chiede di avviare la lavatrice, l'assistente risponde dicendo:

"Il coperchio della lavatrice è aperto. Chiudi e riprova."

Le Eccezioni sono simili agli errori, ma indicano quando un avviso è associato a un comando, il che può o meno bloccare l'esecuzione corretta. Un'eccezione può fornire informazioni correlate utilizzando il trait StatusReport, ad esempio il livello della batteria o una modifica recente dello stato. I codici di eccezione che non bloccano la migrazione vengono restituiti insieme allo stato SUCCESS, mentre i codici di eccezione di blocco vengono restituiti con lo stato EXCEPTIONS.

Un esempio di risposta con un'eccezione è lo snippet di codice seguente:

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "commands": [{
      "ids": ["123"],
      "status": "SUCCESS",
      "states": {
        "online": true,
        "isPaused": false,
        "isRunning": false,
        "exceptionCode": "runCycleFinished"
      }
    }]
  }
}

L'assistente risponde dicendo:

"La lavatrice ha finito."

Per aggiungere i report sugli errori per la lavatrice, apri functions/index.js e aggiungi la definizione della classe di errore come illustrato nel seguente snippet di codice:

index.js

app.onQuery(async (body) => {...});

// Add SmartHome error handling
class SmartHomeError extends Error {
  constructor(errorCode, message) {
    super(message);
    this.name = this.constructor.name;
    this.errorCode = errorCode;
  }
}

Aggiorna la risposta di esecuzione per restituire il codice e lo stato di errore:

index.js

const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
  for (const device of command.devices) {
    for (const execution of command.execution) {
      executePromises.push( ... )
          //Add error response handling
          .catch((error) => {
            functions.logger.error('EXECUTE', device.id, error);
            result.ids.push(device.id);
            if(error instanceof SmartHomeError) {
              result.status = 'ERROR';
              result.errorCode = error.errorCode;
            }
          })
      );
    }
  }
}

Ora l'assistente può comunicare agli utenti qualsiasi codice di errore segnalato. Vedrai un esempio specifico nella sezione successiva.

7. Aggiungi verifica utente secondaria

L'utente dovrebbe implementare la verifica dell'utente secondario nell'Azione se dispone di modalità che devono essere protette o che devono essere limitate a un gruppo specifico di utenti autorizzati, ad esempio un aggiornamento del software o la disattivazione di un blocco.

Puoi implementare la verifica utente secondaria su tutti i tipi e i tratti di dispositivo, personalizzando se la verifica di sicurezza si verifica ogni volta o se è necessario soddisfare criteri specifici.

Esistono tre tipi di sfida supportati:

  • No challenge: una richiesta e una risposta che non utilizza una verifica di autenticazione (comportamento predefinito).
  • ackNeeded: una verifica utente secondaria che richiede una conferma esplicita (sì o no)
  • pinNeeded: una verifica utente secondaria che richiede un PIN (Personal Identification Number).

Per questo codelab, aggiungi una verifica ackNeeded al comando per accendere la lavatrice e la funzionalità per restituire un errore se la verifica secondaria ha esito negativo.

Apri functions/index.js e aggiungi una definizione della classe di errore che restituisca il codice di errore e il tipo di verifica, come indicato nel seguente snippet di codice:

index.js

class SmartHomeError extends Error { ... }

// Add secondary user verification error handling
class ChallengeNeededError extends SmartHomeError {
  /**
   * Create a new ChallengeNeededError
   * @param {string} suvType secondary user verification challenge type
   */
  constructor(suvType) {
    super('challengeNeeded', suvType);
    this.suvType = suvType;
  }
}

Devi anche aggiornare la risposta di esecuzione per restituire l'errore challengeNeeded, nel seguente modo:

index.js

const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
  for (const device of command.devices) {
    for (const execution of command.execution) {
      executePromises.push( ... )
          .catch((error) => {
            functions.logger.error('EXECUTE', device.id, error);
            result.ids.push(device.id);
            if(error instanceof SmartHomeError) {
              result.status = 'ERROR';
              result.errorCode = error.errorCode;
              //Add error response handling
              if(error instanceof ChallengeNeededError) {
                result.challengeNeeded = {
                  type: error.suvType
                };
              }
            }
          })
      );
    }
  }
}

Infine, modifica updateDevice per richiedere la conferma esplicita dell'accensione o dello spegnimento della lavatrice.

index.js

const updateDevice = async (execution,deviceId) => {
  const {challenge,params,command} = execution; //Add secondary user challenge
  let state, ref;
  switch (command) {
    case 'action.devices.commands.OnOff':
      //Add secondary user verification challenge
      if (!challenge || !challenge.ack) {
        throw new ChallengeNeededError('ackNeeded');
      }
      state = {on: params.on};
      ref = firebaseRef.child(deviceId).child('OnOff');
      break;
    ...
  }

  return ref.update(state)
      .then(() => state);
};

Eseguire il deployment in Firebase

Esegui questo comando per eseguire il deployment della funzione aggiornata:

firebase deploy --only functions

Dopo aver eseguito il deployment del codice aggiornato, devi confermare verbalmente l'azione quando chiedi all'assistente di accendere o spegnere la lavatrice, nel seguente modo:

Tu: "Hey Google, accendi la lavatrice."

L'assistente: "Confermi di voler accendere la lavatrice?"

Tu: "Sì."

Puoi anche visualizzare una risposta dettagliata per ogni passaggio del flusso di verifica dell'utente secondario aprendo i log di Firebase.

289dbe48f4bb8106.png

8. Complimenti

674c4f4392e98c1.png

Complimenti! Hai esteso le funzionalità di Azioni per la smart home tramite i trait Modes e Toggles e ne hai protetto l'esecuzione tramite la verifica utente secondaria.

Scopri di più

Ecco alcune idee che puoi implementare per approfondire:

  • Aggiungi funzionalità di esecuzione locale ai tuoi dispositivi.
  • Utilizza un tipo di verifica utente secondaria diverso per modificare lo stato del dispositivo.
  • Aggiorna la risposta QUERY del trait RunCycle in modo che venga aggiornata in modo dinamico.
  • Esplora questo esempio di GitHub.