Collegare i dispositivi per la smart home all'Assistente Google

1. Prima di iniziare

In qualità di sviluppatore di Internet of Things (IoT), puoi creare integrazioni cloud-to-cloud che offrono agli utenti la possibilità di controllare i propri dispositivi tramite i controlli touch nell'app Google Home e i comandi vocali con l'assistente.

79266e5f45e6ae20.gif

Le integrazioni cloud-to-cloud si basano su Home Graph per fornire dati contestuali sulla casa e sui suoi dispositivi, creando una mappa logica della casa. Questo contesto consente all'assistente di comprendere in modo più naturale le richieste dell'utente in base alla sua posizione in casa. Ad esempio, Home Graph può memorizzare il concetto di un salotto contenente più tipi di dispositivi di diversi produttori, come termostato, lampada, ventilatore e aspirapolvere.

d009cef0f903d284.jpeg

Prerequisiti

Cosa creerai

In questo codelab, pubblicherai un servizio cloud che gestisce una lavatrice smart virtuale, quindi creerai un'integrazione cloud-to-cloud e la collegherai all'assistente.

Cosa imparerai a fare

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

Che cosa ti serve

2. Per iniziare

Abilitare Gestione attività

Per utilizzare l'Assistente Google, devi condividere determinati dati sulle tue attività con Google. L'Assistente Google ha bisogno di questi dati per funzionare correttamente, ma il requisito di condivisione dei dati non è specifico per l'SDK. Per condividere questi dati, crea un Account Google, se non ne hai già uno. Puoi utilizzare qualsiasi Account Google, non deve essere il tuo account sviluppatore.

Apri la pagina Gestione attività per l'Account Google che vuoi utilizzare con l'assistente.

Assicurati che i seguenti pulsanti di attivazione/disattivazione siano attivati:

  • Attività web e app: inoltre, 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 sul dispositivo
  • Attività vocale e audio

Creare un progetto di integrazione cloud-to-cloud

  1. Vai a Developer Console.
  2. Fai clic su Crea progetto, inserisci un nome per il progetto e fai clic su Crea progetto.

Assegna un nome al progetto

Seleziona l'integrazione cloud-to-cloud

Nella home page del progetto nella Console per gli sviluppatori, seleziona Aggiungi integrazione cloud-to-cloud in Cloud-to-cloud.

Aggiungi l'integrazione cloud-to-cloud

Installa l'interfaccia a riga di comando di Firebase

L'interfaccia a riga di comando (CLI) di Firebase ti consente di pubblicare le app web localmente e di eseguire il deployment delle app web su Firebase Hosting.

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

npm install -g firebase-tools

Per verificare che la CLI 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 avvio

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 il Sample per questo codelab sulla tua macchina di sviluppo:

Puoi anche clonare 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 lavatrice smart con Cloud Functions per Firebase e Firebase Realtime Database.

Creare un progetto Firebase

  1. Vai a Firebase.
  2. Fai clic su Crea un progetto e inserisci il nome del progetto.
  3. Seleziona la casella di controllo del contratto e fai clic su Continua. Se non è presente la casella di controllo del contratto, puoi saltare questo passaggio.
    Crea un progetto Firebase
  4. Una volta creato il progetto Firebase, individua l'ID progetto. Vai a Panoramica del progetto e fai clic sull'icona delle impostazioni > Impostazioni progetto.
    Apri le impostazioni del progetto
  5. Il progetto è elencato nella scheda Generali.
    Impostazioni generali del progetto

Connettersi a Firebase

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

cd washer-start
firebase use <firebase-project-id>

Configura il progetto Firebase

Inizializza un progetto Firebase.

firebase init

Seleziona le funzionalità dell'interfaccia a riga di comando, Realtime Database, Functions 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

Verranno inizializzate le API e le funzionalità necessarie per il progetto.

Quando richiesto, inizializza Realtime Database. Puoi utilizzare la posizione predefinita per l'istanza del 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 di 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 una base di codice.

? 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 nel progetto di esempio.

? 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 da utilizzare la directory public nel codice del progetto e utilizza 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, sono disponibili due metodi per disattivarlo:

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

Nel file washer-done/firebase.json, completa il codice con:

{
  "database": {
    "rules": "database.rules.json"
  },
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },
    "headers": [{
      "source" : "**/*.@(js|html)",
      "headers" : [ {
        "key" : "Cache-Control",
        "value" : "max-age=0"
      } ]
    }],
  "functions": [
    {
      "source": "functions",
      "codebase": "default",
      "ignore": [
        "node_modules",
        ".git",
        "firebase-debug.log",
        "firebase-debug.*.log",
        "*.local"
      ]
    }
  ]
}

Esegui 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/<firebase-project-id>/overview
Hosting URL: https://<firebase-project-id>.web.app

Questo comando esegue il deployment di un'app web e di diverse funzioni Cloud per Firebase.

Apri l'URL di hosting nel browser (https://.web.app) per visualizzare l'app web. Vedrai la seguente interfaccia:

5845443e94705557.png

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

Ora è il momento di collegare il servizio cloud di cui hai eseguito il deployment all'Assistente Google utilizzando la console per sviluppatori Google Home.

Configurare il progetto Developers Console

Nella scheda Sviluppa, aggiungi un Nome visualizzato per l'interazione. Questo nome verrà visualizzato nell'app Google Home.

Aggiungere un nome visualizzato

In Branding dell'app, carica un file png per l'icona dell'app, di dimensioni 144 x 144 px e denominato .png.

Aggiungere un&#39;icona dell&#39;app

Per attivare il collegamento dell'account, utilizza queste impostazioni:

ID client

ABC123

Client secret

DEF456

URL autorizzazione

https://us-central1-
.cloudfunctions.net/fakeauth

URL token

https://us-central1-
.cloudfunctions.net/faketoken

Aggiornare gli URL di collegamento dell&#39;account

In URL di adempimento cloud, inserisci l'URL della funzione cloud che fornisce l'adempimento per gli intent per la smart home.

https://us-central1--cloudfunctions.net/smarthome

Aggiungi l&#39;URL della funzione cloud

Fai clic su Salva per salvare la configurazione del progetto, poi fai clic su Avanti: test per attivare i test nel progetto.

Testa l&#39;integrazione cloud-to-cloud

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

4. Creare una rondella

Ora che hai configurato l'integrazione, puoi aggiungere dispositivi e inviare dati. Il tuo servizio cloud deve gestire le seguenti intenzioni:

  • Un'intenzione SYNC si verifica quando l'assistente vuole sapere quali dispositivi l'utente ha connesso. Viene inviato al tuo servizio quando l'utente collega un account. Devi rispondere con un payload JSON di tutti i dispositivi dell'utente e delle relative funzionalità.
  • Un'intenzione QUERY si verifica quando l'assistente vuole conoscere lo stato attuale di un dispositivo. Devi rispondere con un payload JSON con lo stato di ogni dispositivo richiesto.
  • Un'intenzione 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'intenzione DISCONNECT si verifica quando l'utente scollega il proprio account dall'assistente. Devi interrompere l'invio di eventi per i dispositivi di questo utente all'assistente.

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

Aggiornare la risposta SYNC

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

Dovrai gestire un'intent SYNC restituendo le funzionalità e i metadati del dispositivo. Aggiorna il JSON nell'array onSync in modo da includere le informazioni sul dispositivo e le caratteristiche consigliate 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,
        },
      }],
    },
  };
});

Esegui il deployment in Firebase

Esegui il deployment dell'implementazione cloud aggiornata utilizzando l'interfaccia a riga di comando di Firebase:

firebase deploy --only functions

Per testare l'integrazione cloud-to-cloud, devi collegare il tuo progetto a un Account Google. In questo modo puoi eseguire test tramite le piattaforme dell'Assistente Google e l'app Google Home su cui hai eseguito l'accesso allo stesso account.

  1. Apri le impostazioni dell'Assistente Google sullo smartphone. Tieni presente che devi aver eseguito l'accesso con lo stesso account utilizzato nella console.
  2. Vai ad Assistente Google > Impostazioni > Controllo della casa (nella sezione 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 si autentica quindi con il tuo servizio e invia una richiesta SYNC chiedendo al tuo servizio di fornire un elenco di dispositivi per l'utente.

Apri l'app Google Home e verifica di poter vedere la lavatrice.

ae252220753726f6.png

5. Gestire comandi e query

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

Gestire l'intenzione QUERY

Un'intent QUERY include un insieme di dispositivi. Per ogni dispositivo, devi rispondere con il relativo stato corrente.

In functions/index.js, modifica l'handler 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, restituisce lo stato corrente archiviato nel database in tempo reale. Aggiorna le funzioni queryFirebase e queryDevice per restituire i dati dello 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'intenzione 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 l'handler EXECUTE per elaborare l'elenco di tratti che richiedono aggiornamenti e l'insieme di dispositivi target per ogni 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 database in tempo reale corrispondenti al tratto richiesto. Modifica la funzione updateDevice per aggiornare il riferimento Firebase appropriato e restituire lo stato del dispositivo aggiornato.

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 = params.start
      ? {isRunning: true, isPaused: false}
      : {isRunning: false, isPaused: false};
      ref = firebaseRef.child(deviceId).child('StartStop');
      break;
    case 'action.devices.commands.PauseUnpause':
      const data = await queryDevice(deviceId);
      state = (data.isPaused === false && data.isRunning === false)
        ? {isRunning: false, isPaused: false}
        : {isRunning: !params.pause, isPaused: params.pause};
      ref = firebaseRef.child(deviceId).child('StartStop');
      break;
  }

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

6. Testa l'integrazione

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

Esegui il deployment in Firebase

Esegui il deployment dell'implementazione cloud aggiornata utilizzando l'interfaccia a riga di comando di Firebase:

firebase deploy --only functions

Testa la lavatrice

Ora puoi vedere la variazione del valore quando provi uno dei seguenti comandi vocali tramite lo smartphone:

"Hey Google, accendi la lavatrice."

"Hey Google, metti in pausa la lavatrice."

"Hey Google, interrompi la lavatrice."

Puoi anche vedere lo stato attuale della lavatrice ponendo delle domande.

"Hey Google, la mia lavatrice è accesa?"

"Hey Google, la mia lavatrice è in funzione?"

"Hey Google, qual è il ciclo della mia lavatrice?"

Puoi visualizzare queste query e questi comandi nei log visualizzati sotto la funzione nella sezione Funzioni della Console Firebase. Scopri di più sui log di Firebase in Scrivere e visualizzare i log.

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

7. Segnalare gli aggiornamenti a Google

Hai integrato completamente il tuo servizio cloud con gli intent per la smart home, consentendo agli utenti di controllare e eseguire query sullo stato attuale dei loro dispositivi. Tuttavia, l'implementazione non prevede ancora un modo per consentire al tuo 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 oppure quando le funzionalità dei dispositivi cambiano. Con Report State, il tuo servizio cloud può inviare in modo proattivo lo stato di un dispositivo a Home Graph quando gli utenti cambiano fisicamente lo stato di un dispositivo, ad esempio accendendo un interruttore della luce, o lo cambiano utilizzando un altro servizio.

In questa sezione aggiungerai il codice per chiamare questi metodi dall'applicazione web di frontend.

Abilita l'API HomeGraph

L'API HomeGraph consente di archiviare e eseguire query sui dispositivi e sui relativi 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 corrispondente all'integrazione <project-id>.. Quindi, nella schermata Libreria API per l'API HomeGraph, fai clic su Attiva.

ee198858a6eac112.png

Attivare lo stato del report

Le scritture in Realtime Database attivano la funzione reportstate nel progetto iniziale. Aggiorna la funzione reportstate in functions/index.js per acquisire i dati scritti nel database e pubblicarli nel grafico della casa 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);
    });

Attivare la sincronizzazione delle richieste

L'aggiornamento dell'icona nell'interfaccia utente web del frontend attiva la funzione requestsync nel progetto iniziale. 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}`);
  }
});

Esegui 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 di visualizzare una richiesta di sincronizzazione nel log della Console Firebase.

A questo punto, modifica gli attributi del dispositivo della lavatrice nell'interfaccia utente web frontend e fai clic su Aggiorna. Verifica di poter vedere la modifica dello stato segnalata a Google nei log della console Firebase.

8. Complimenti

674c4f4392e98c1.png

Complimenti! Hai integrato l'assistente con un servizio cloud per dispositivi utilizzando le integrazioni cloud-to-cloud.

Scopri di più

Ecco alcune idee che puoi implementare per approfondire:

Puoi anche scoprire di più su come testare e inviare un'integrazione per la revisione, inclusa la procedura di certificazione per pubblicare l'integrazione per gli utenti.