Collegare i dispositivi per la smart home all'Assistente Google

1. Prima di iniziare

In qualità di sviluppatore IoT (Internet of Things), puoi creare azioni per la smart home che consentono agli utenti di controllare i propri dispositivi tramite i controlli touch nell'app Google Home e i comandi vocali con l'assistente.

79266e5f45e6ae20.gif

Le azioni della smart home si basano su Home Graph per fornire dati contestuali sulla casa e sui suoi dispositivi, creando una mappa logica della casa. Tale contesto permette all'assistente di comprendere in modo più naturale le richieste dell'utente in relazione alla sua posizione in casa. Ad esempio, Home Graph può memorizzare l'idea di un salotto che contiene più tipi di dispositivi di diversi produttori, come un termostato, una lampada, un ventilatore e un aspirapolvere.

d009cef0f903d284.jpeg

Prerequisiti

Cosa creerai

In questo codelab pubblicherai un servizio cloud che gestisce una lavatrice smart virtuale, quindi creerai un'azione per la smart home e la collegherai all'assistente.

Cosa imparerai a fare

  • Come eseguire il deployment di un servizio cloud per la smart home
  • Come collegare il tuo servizio all'assistente
  • Come pubblicare le modifiche dello stato del dispositivo su Google

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

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-washer.git

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.

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
    

Per assicurarti di avere una configurazione Firebase corretta e completa, copia il file firebase.json dalla directory app-done alla directory app-start, sovrascrivendo quello in app-start.

Nella directory app-start:

cp -vp ../app-done/firebase.json .

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

Ora puoi iniziare a implementare i webhook necessari per connettere lo stato del dispositivo all'assistente.

4. Crea una lavatrice

Ora che hai configurato l'Azione, puoi aggiungere dispositivi e inviare dati. Il tuo servizio cloud deve gestire i seguenti intent:

  • Un intent SYNC si verifica quando l'assistente vuole sapere quali dispositivi ha collegato l'utente. Viene inviato al tuo servizio quando l'utente collega un account. Dovresti rispondere con un payload JSON di tutti i dispositivi dell'utente e delle loro funzionalità.
  • Un intent QUERY si verifica quando l'assistente vuole conoscere lo stato o lo stato attuale di un dispositivo. Devi rispondere con un payload JSON con lo stato di ogni dispositivo richiesto.
  • Un intent EXECUTE si verifica quando l'assistente vuole controllare un dispositivo per conto di un utente. Devi rispondere con un payload JSON con lo stato di esecuzione di ogni dispositivo richiesto.
  • Un intent DISCONNECT si verifica quando l'utente scollega il proprio account dall'assistente. Non dovresti più inviare all'assistente gli eventi dei dispositivi di questo utente.

Nelle sezioni seguenti aggiornerai le funzioni di cui hai eseguito il deployment in precedenza per gestire questi intent.

Aggiorna la risposta SYNC

Apri functions/index.js, che contiene il codice per rispondere alle richieste dell'assistente.

Dovrai gestire un intent SYNC restituendo i metadati e le funzionalità del dispositivo. Aggiorna il codice JSON nell'array onSync in modo che includa le informazioni del dispositivo e i trait consigliati per una lavatrice.

index.js

app.onSync((body) => {
  return {
    requestId: body.requestId,
    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',
        ],
        name: {
          defaultNames: ['My Washer'],
          name: 'Washer',
          nicknames: ['Washer'],
        },
        deviceInfo: {
          manufacturer: 'Acme Co',
          model: 'acme-washer',
          hwVersion: '1.0',
          swVersion: '1.0.1',
        },
        willReportState: true,
        attributes: {
          pausable: true,
        },
      }],
    },
  };
});

Eseguire il deployment in Firebase

Esegui il deployment del Cloud fulfillment aggiornato utilizzando l'interfaccia a riga di comando di Firebase:

firebase deploy --only functions

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

5. Gestire comandi e query

Ora che il servizio cloud segnala correttamente il dispositivo lavaggio a Google, devi aggiungere la possibilità di richiedere lo stato del dispositivo e inviare comandi.

Gestire l'intent QUERY

Un intent QUERY include un insieme di dispositivi. Per ogni dispositivo, devi rispondere con il suo stato attuale.

In functions/index.js, modifica il gestore QUERY per elaborare l'elenco dei dispositivi di destinazione contenuti nella richiesta di intent.

index.js

app.onQuery(async (body) => {
  const {requestId} = body;
  const payload = {
    devices: {},
  };
  const queryPromises = [];
  const intent = body.inputs[0];
  for (const device of intent.payload.devices) {
    const deviceId = device.id;
    queryPromises.push(queryDevice(deviceId)
        .then((data) => {
        // Add response to device payload
          payload.devices[deviceId] = data;
        }
        ));
  }
  // Wait for all promises to resolve
  await Promise.all(queryPromises);
  return {
    requestId: requestId,
    payload: payload,
  };
});

Per ogni dispositivo contenuto nella richiesta, restituisci lo stato corrente archiviato nel Realtime Database. Aggiorna le funzioni queryFirebase e queryDevice per restituire i dati sullo stato della lavatrice.

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,
  };
};

const queryDevice = async (deviceId) => {
  const data = await queryFirebase(deviceId);
  return {
    on: data.on,
    isPaused: data.isPaused,
    isRunning: data.isRunning,
    currentRunCycle: [{
      currentCycle: 'rinse',
      nextCycle: 'spin',
      lang: 'en',
    }],
    currentTotalRemainingTime: 1212,
    currentCycleRemainingTime: 301,
  };
};

Gestire l'intent EXECUTE

L'intent EXECUTE gestisce i comandi per aggiornare lo stato del dispositivo. La risposta restituisce lo stato di ciascun comando, ad esempio SUCCESS, ERROR o PENDING, e il nuovo stato del dispositivo.

In functions/index.js, modifica il gestore EXECUTE per elaborare l'elenco di trait che richiedono aggiornamenti e l'insieme di dispositivi di destinazione per ciascun comando:

index.js

app.onExecute(async (body) => {
  const {requestId} = body;
  // Execution results are grouped by status
  const result = {
    ids: [],
    status: 'SUCCESS',
    states: {
      online: true,
    },
  };

  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(
            updateDevice(execution, device.id)
                .then((data) => {
                  result.ids.push(device.id);
                  Object.assign(result.states, data);
                })
                .catch(() => functions.logger.error('EXECUTE', device.id)));
      }
    }
  }

  await Promise.all(executePromises);
  return {
    requestId: requestId,
    payload: {
      commands: [result],
    },
  };
});

Per ogni comando e dispositivo di destinazione, aggiorna i valori nel Realtime Database che corrispondono al trait richiesto. Modifica la funzione updateDevice per aggiornare il riferimento Firebase appropriato e restituire lo stato aggiornato del dispositivo.

index.js

const updateDevice = async (execution, deviceId) => {
  const {params, command} = execution;
  let state; let 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;
  }

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

6. Testare l'azione

Dopo aver implementato tutti e tre gli intent, puoi verificare che l'Azione controlli la lavatrice.

Eseguire il deployment in Firebase

Esegui il deployment del Cloud fulfillment aggiornato utilizzando l'interfaccia a riga di comando di Firebase:

firebase deploy --only functions

Prova la lavatrice

Ora puoi vedere la variazione del valore quando provi uno dei seguenti comandi vocali dal telefono:

"Hey Google, accendi la lavatrice."

"Hey Google, metti in pausa la lavatrice."

"Hey Google, interrompi la lavatrice."

Puoi anche controllare lo stato attuale della lavatrice facendo delle domande.

"Hey Google, la lavatrice è accesa?"

"Hey Google, la lavatrice è accesa?"

"Hey Google, a che ciclo è la lavatrice?"

Puoi visualizzare queste query e questi comandi nei log visualizzati nella tua funzione nella sezione Funzioni della Console di Firebase. Per saperne di più sui log di Firebase, consulta Scrivere e visualizzare i log.

Puoi trovare queste query e questi comandi anche nella console Google Cloud andando su Logging > Esplora log. Scopri di più sul logging di Google Cloud in Accedere ai log eventi con Cloud Logging.

7. Segnalare aggiornamenti a Google

Hai integrato completamente il servizio cloud con gli intent della smart home, consentendo agli utenti di controllare ed eseguire query sullo stato attuale dei propri dispositivi. Tuttavia, nell'implementazione manca ancora un modo per consentire al servizio di inviare in modo proattivo all'assistente informazioni sugli eventi, ad esempio le modifiche alla presenza o allo stato del dispositivo.

Con Richiedi sincronizzazione, puoi attivare una nuova richiesta di sincronizzazione quando gli utenti aggiungono o rimuovono dispositivi o quando le funzionalità dei loro dispositivi cambiano. Con lo stato del report, il servizio cloud può inviare in modo proattivo lo stato di un dispositivo a Home Graph quando gli utenti cambiano fisicamente uno stato del dispositivo, ad esempio accendendo un interruttore della luce, o lo cambiano utilizzando un altro servizio.

In questa sezione, aggiungerai codice per chiamare questi metodi dall'app web frontend.

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

Attiva stato del report

Scrive nel trigger di Realtime Database per la funzione reportstate nel progetto di partenza. Aggiorna la funzione reportstate in functions/index.js per acquisire i dati scritti nel database e pubblicarli su Home Graph tramite lo stato del report.

index.js

exports.reportstate = functions.database.ref('{deviceId}').onWrite(
    async (change, context) => {
      functions.logger.info('Firebase write event triggered Report State');
      const snapshot = change.after.val();

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

      const res = await homegraph.devices.reportStateAndNotification({
        requestBody,
      });
      functions.logger.info('Report state response:', res.status, res.data);
    });

Abilita sincronizzazione richieste

L'aggiornamento dell'icona nell'interfaccia utente web di frontend attiva la funzione requestsync nel progetto di partenza. Implementa la funzione requestsync in functions/index.js per chiamare l'API HomeGraph.

index.js

exports.requestsync = functions.https.onRequest(async (request, response) => {
  response.set('Access-Control-Allow-Origin', '*');
  functions.logger.info(`Request SYNC for user ${USER_ID}`);
  try {
    const res = await homegraph.devices.requestSync({
      requestBody: {
        agentUserId: USER_ID,
      },
    });
    functions.logger.info('Request sync response:', res.status, res.data);
    response.json(res.data);
  } catch (err) {
    functions.logger.error(err);
    response.status(500).send(`Error requesting sync: ${err}`);
  }
});

Eseguire il deployment in Firebase

Esegui il deployment del codice aggiornato utilizzando l'interfaccia a riga di comando di Firebase:

firebase deploy --only functions

Verificare la tua implementazione

Fai clic sul pulsante Aggiorna ae8d3b25777a5e30.png nell'interfaccia utente web e verifica la visualizzazione di una richiesta di sincronizzazione nel log della console Firebase.

Dopodiché modifica gli attributi del dispositivo lavaggio nell'interfaccia utente web di frontend e fai clic su Aggiorna. Verifica di poter vedere il cambiamento di stato segnalato a Google nei log della Console Firebase.

8. Complimenti

674c4f4392e98c1.png

Complimenti! Hai integrato correttamente l'assistente con un servizio cloud del dispositivo utilizzando le azioni per la smart home.

Scopri di più

Ecco alcune idee che puoi implementare per approfondire:

Scopri di più su come testare e inviare un'Azione per la revisione, inclusa la procedura di certificazione per la pubblicazione dell'Azione per gli utenti.