שיפור ואבטחה של פעולות בבית החכם

1. לפני שמתחילים

הפעולות בבית החכם מתבססות על סוגי מכשירים כדי לאפשר ל-Google Assistant לדעת באיזה דקדוק צריך להשתמש במכשיר. traits של המכשיר מגדירות את היכולות של סוגי המכשירים. מכשיר יורש את המצבים של כל תכונה של המכשיר שמתווספת לפעולה.

dc8dce0dea87cd5c.png

אפשר לחבר כל תכונה נתמכת לסוג המכשיר שבחרת כדי להתאים אישית את הפונקציונליות של המכשירים של המשתמשים. אם רוצים להטמיע תכונות מותאמות אישית בפעולות שלא זמינות כרגע בסכימת המכשיר, התכונות מצבים והחלפה מאפשרות שליטה של הגדרות ספציפיות באמצעות שם מותאם אישית.

מעבר ליכולת השליטה הבסיסית, לפי סוגים ותכונות, Smart Home API כולל תכונות נוספות לשיפור חוויית המשתמש. תגובות לשגיאות מספקות משוב מפורט מהמשתמשים, במקרים שבהם הכוונות לא מצליחות. אימות משתמש משני מרחיב את התגובות האלה ומוסיף עוד אבטחה לתכונת המכשיר שבחרתם. שליחת תגובות ספציפיות לשגיאות בחסימות של חסימות שהונפקו על ידי Assistant, עשויה לחייב הרשאה נוספת לביצוע פקודה בבית החכם.

דרישות מוקדמות

מה תפַתחו

בשיעור ה-codelab הזה תפרסו שילוב מובנה מראש של בית חכם עם Firebase, ואז תלמדו איך להוסיף תכונות לא סטנדרטיות למכונת הכביסה לבית החכם לפי גודל הטעינה ומצב טורבו. תוכלו גם להטמיע דיווח על שגיאות וחריגות, וגם ללמוד איך לאכוף אישור מילולי כדי להפעיל את מכונת הכביסה באמצעות אימות משתמש משני.

מה תלמדו

  • איך מוסיפים את המצבים ואת החלפת התכונות לפעולה
  • איך מדווחים על שגיאות וחריגים
  • איך מחילים אימות משתמש משני

מה הדרישות כדי להצטרף לתוכנית?

2. איך מתחילים

הפעלה של בקרת הפעילות בחשבון

כדי להשתמש ב-Google Assistant, צריך לשתף נתוני פעילות מסוימים עם Google. הנתונים האלה נדרשים ל-Google Assistant כדי לפעול באופן תקין. עם זאת, הדרישה לשיתוף נתונים אינה ספציפית ל-SDK. כדי לשתף את הנתונים האלה, צריך ליצור חשבון Google, אם עדיין אין לכם חשבון. אפשר להשתמש בכל חשבון Google — זה לא חייב להיות חשבון הפיתוח שלך.

פותחים את הדף 'בקרת הפעילות בחשבון' עבור חשבון Google שבו רוצים להשתמש עם Assistant.

צריך לוודא שמתגי החלפת המצב הבאים מופעלים:

  • פעילות באינטרנט ובאפליקציות – נוסף על כך, צריך לסמן את התיבה ההגדרה הזו כוללת את ההיסטוריה והפעילות של Chrome מאתרים, מאפליקציות וממכשירים המשתמשים בשירותי Google.
  • מידע מהמכשירים שלך
  • פעילות קול ואודיו

יצירת פרויקט ל'פעולות'

  1. עוברים אל Actions on Google Developer Console.
  2. לוחצים על פרויקט חדש, נותנים שם לפרויקט ולוחצים על יצירת פרויקט.

3d6b68ca79afd54c.png

בחירה של אפליקציית הבית החכם

במסך הסקירה הכללית במסוף Actions, בוחרים באפשרות בית חכם.

2fa4988f44f8914b.png

בוחרים בכרטיס של חוויית הבית החכם, לוחצים על התחלת הבנייה ומשם תועברו אל מסוף הפרויקט.

התקנת ה-CLI של Firebase

ממשק שורת הפקודה (CLI) של Firebase מאפשר להציג את אפליקציות האינטרנט באופן מקומי ולפרוס את אפליקציית האינטרנט באירוח ב-Firebase.

כדי להתקין את ה-CLI, מריצים את פקודת ה-npm הבאה מהטרמינל:

npm install -g firebase-tools

כדי לוודא שה-CLI הותקן כראוי, מריצים את:

firebase --version

מאשרים את ה-CLI של Firebase באמצעות חשבון Google על ידי הרצת:

firebase login

הפעלת HomeGraph API

HomeGraph API מאפשר לאחסן מכשירים והמצבים שלהם בתרשים הבית של המשתמש ולשלוח שאילתות לגביהם. כדי להשתמש ב-API הזה, קודם צריך לפתוח את מסוף Google Cloud ולהפעיל את HomeGraph API.

במסוף Google Cloud, בוחרים את הפרויקט שתואם לפעולות <project-id>.. לאחר מכן, במסך 'ספריית API' של HomeGraph API, לוחצים על הפעלה.

ee198858a6eac112.png

3. הפעלת האפליקציה לתחילת הדרך

עכשיו, אחרי שמגדירים את סביבת הפיתוח, אפשר לפרוס את הפרויקט לתחילת העבודה כדי לוודא שהכול מוגדר כראוי.

איך מקבלים את קוד המקור

כדי להוריד למחשב הפיתוח את הדוגמה של Codelab זה, יש ללחוץ על הקישור הבא:

...או שאפשר לשכפל את המאגר של GitHub משורת הפקודה:

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

פותחים את קובץ ה-ZIP שהורד.

מידע על הפרויקט

הפרויקט לתחילת העבודה מכיל את ספריות המשנה הבאות:

  • public: ממשק משתמש חזיתי שמאפשר לשלוט בקלות במצב של מכונת הכביסה החכמה ולנטר אותה.
  • functions: שירות ענן מוטמע במלואו שמנהל את מכונת הכביסה החכמה באמצעות Cloud Functions for Firebase ומסד נתונים בזמן אמת ב-Firebase.

מילוי הבקשה בענן כולל את הפונקציות הבאות ב-index.js:

  • fakeauth: נקודת קצה להרשאה לקישור חשבונות
  • faketoken: נקודת קצה של אסימון לקישור חשבונות
  • smarthome: נקודת קצה למילוי Intent בבית חכם
  • reportstate: הפעלת ממשק ה-API של Home Graph בשינויים במצב המכשיר
  • requestsync: מאפשר עדכונים למכשיר של משתמשים בלי שיהיה צורך לקשר מחדש את החשבון

קישור ל-Firebase

עוברים לספרייה washer-start ומגדירים את ה-CLI של Firebase בפרויקט הפעולות:

cd washer-start
firebase use <project-id>

הגדרת פרויקט Firebase

מפעילים פרויקט Firebase.

firebase init

בוחרים את תכונות ה-CLI, מסד נתונים בזמן אמת, פונקציות, והתכונה אירוח שכוללת את האירוח ב-Firebase.

? 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

הפעולה הזו תפעיל את התכונות וממשקי ה-API הנחוצים לפרויקט שלכם.

כשתתבקשו, הפעילו את מסד הנתונים בזמן אמת. אתם יכולים להשתמש במיקום ברירת המחדל של המופע של מסד הנתונים.

? 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

מכיוון שבחרת להשתמש בקוד הפרויקט למתחילים, עליך לבחור את קובץ ברירת המחדל של כללי האבטחה ולוודא שלא מחליפים את קובץ כללי מסד הנתונים הקיים.

? 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

אם אתם מאתחלים מחדש את הפרויקט, כשתישאלו אם אתם רוצים לאתחל או להחליף קוד בסיס, עליכם לבחור באפשרות Overwrite (החלפה).

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

כשמגדירים את הפונקציות, יש להשתמש בקובצי ברירת המחדל, ולוודא שלא מחליפים את הקבצים index.js ו-package.json הקיימים בדוגמת הפרויקט.

? 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

אם אתם מאתחלים מחדש את הפרויקט, כשתישאלו אם אתם רוצים לאתחל או להחליף פונקציות/.gitignore, יש לבחור באפשרות לא.

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

לסיום, צריך להגדיר את הגדרת האירוח להשתמש בספרייה public בקוד הפרויקט, ולהשתמש בקובץ index.html הקיים. בוחרים באפשרות לא כשמתבקשים להשתמש ב-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

אם ESLint הופעל בטעות, יש שתי שיטות זמינות להשבית אותו:

  1. באמצעות ה-GUI, עוברים לתיקייה ../functions בפרויקט, בוחרים את הקובץ המוסתר .eslintrc.js ומוחקים אותו. אין בעיה עם השם הדומה .eslintrc.json.
  2. באמצעות שורת הפקודה:
    cd functions
    rm .eslintrc.js
    

פריסה ב-Firebase

עכשיו, לאחר שהתקנתם את יחסי התלות והגדרת את הפרויקט, אתם מוכנים להפעיל את האפליקציה בפעם הראשונה.

firebase deploy

זה הפלט של המסוף שאתם אמורים לראות:

...

✔ Deploy complete!

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

הפקודה הזו פרסה אפליקציית אינטרנט יחד עם כמה Cloud Functions for Firebase.

יש לפתוח את כתובת ה-URL לאירוח בדפדפן (https://<project-id>.web.app) כדי להציג את אפליקציית האינטרנט. יוצג הממשק הבא:

5845443e94705557.png

ממשק המשתמש הזה באינטרנט מייצג פלטפורמה של צד שלישי להצגה או לשינוי של מצבי המכשיר. כדי להתחיל לאכלס את מסד הנתונים במידע מהמכשירים שלך, לוחצים על עדכון. לא יופיעו שינויים בדף, אבל המצב הנוכחי של מכונת הכביסה יישמר במסד הנתונים.

עכשיו הגיע הזמן לחבר את שירות הענן שפרסתם אל Google Assistant באמצעות Actions Console.

הגדרת הפרויקט במסוף Actions

בקטע סקירה כללית > בניית הפעולה, בוחרים באפשרות הוספת פעולות. מזינים את כתובת ה-URL של הפונקציה ב-Cloud Functions שמספקת מילוי הזמנות עבור ה-Intents של הבית החכם ולוחצים על שמירה.

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

9d7b223427f587ca.png

בכרטיסייה פיתוח > הפעלה, מוסיפים שם תצוגה לפעולה ולוחצים על שמירה. השם הזה יופיע באפליקציית Google Home.

774d0c40c351c7da.png

a8c4673eb11d76ee.png

כדי להפעיל את קישור החשבונות, בוחרים באפשרות פיתוח > קישור חשבון בתפריט הניווט הימני. השתמש בהגדרות הבאות לקישור חשבונות:

Client ID

ABC123

סוד לקוח

DEF456

כתובת אתר להרשאה

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

כתובת ה-URL של האסימון

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

9730d20b90bcc038.png

לוחצים על Save כדי לשמור את הגדרת הקישור של החשבון, ואז לוחצים על Test כדי להפעיל את הבדיקה בפרויקט.

ee0547f05b5efd98.png

המערכת תפנה אתכם אל הסימולטור. אם לא מופיעה האפשרות הבדיקה מופעלת, לוחצים על איפוס הבדיקה כדי לוודא שהבדיקה מופעלת.

d0495810dbadf059.png

כדי לבדוק את הפעולה בבית החכם, צריך לקשר את הפרויקט לחשבון Google. כך אפשר לבצע בדיקות בפלטפורמות של Google Assistant ובאפליקציית Google Home, שמחוברים לאותו חשבון.

  1. בטלפון, פותחים את ההגדרות של Google Assistant. שימו לב: עליכם להיות מחוברים לאותו חשבון כמו במסוף.
  2. עוברים אל Google Assistant > הגדרות > בית חכם (בקטע Assistant).
  3. לוחצים על סמל החיפוש בפינה השמאלית העליונה.
  4. מחפשים את אפליקציית הבדיקה באמצעות הקידומת [test] כדי למצוא את אפליקציית הבדיקה הספציפית.
  5. בוחרים בפריט הזה. לאחר מכן, Google Assistant תבצע אימות מול השירות שלך ותשלח בקשת SYNC, עם בקשה מהשירות לספק רשימת מכשירים למשתמש.

פותחים את אפליקציית Google Home ומוודאים שאפשר לראות את מכונת הכביסה.

ae252220753726f6.png

חשוב לוודא שאתם יכולים לשלוט במכונת הכביסה באמצעות פקודות קוליות באפליקציית Google Home. בנוסף, מצב המכשיר אמור להופיע בממשק המשתמש של ממשק הקצה באינטרנט של מילוי ההזמנות בענן.

עכשיו, אחרי פריסה של מכונת כביסה בסיסית, אפשר להתאים אישית את המצבים הזמינים במכשיר.

4. הוספת מצבים

המאפיין action.devices.traits.Modes מאפשר למכשיר לקבל מספר שרירותי של הגדרות למצב, שיש בו רק אפשרות אחת בכל פעם. מוסיפים מצב למכונת הכביסה כדי להגדיר את גודל מכונת הכביסה: קטנה, בינונית או גדולה.

עדכון תגובת הסנכרון

עליך להוסיף מידע על התכונה החדשה לתשובה שלך מסוג SYNC בfunctions/index.js. הנתונים האלה מופיעים במערך traits ובאובייקט attributes כפי שמוצג בקטע הקוד הבא.

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

הוספה של פקודות EXECUTE חדשות של Intent

ב-Intent EXECUTE, מוסיפים את הפקודה action.devices.commands.SetModes כפי שמוצג בקטע הקוד הבא.

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

עדכון התשובה QUERY

בשלב הבא צריך לעדכן את התשובה של QUERY כדי לדווח על המצב הנוכחי של מכונת הכביסה.

מוסיפים את השינויים המעודכנים לפונקציות queryFirebase ו-queryDevice כדי לקבל את המצב כפי שנשמר במסד הנתונים בזמן אמת.

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

עדכון מצב הדוח

לסיום, צריך לעדכן את הפונקציה reportstate כדי לדווח על הגדרת העומס הנוכחית של מכונת הכביסה לתרשים הבית.

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

פריסה ב-Firebase

מריצים את הפקודה הבאה כדי לפרוס את הפעולה המעודכנת:

firebase deploy --only functions

בסיום הפריסה, עוברים לממשק המשתמש ולוחצים על הלחצן רענן ae8d3b25777a5e30.png בסרגל הכלים. הפעולה הזו מפעילה סנכרון של בקשות כדי ש-Assistant תקבל את נתוני התגובה המעודכנים של SYNC.

bf4f6a866160a982.png

עכשיו אתם יכולים לתת פקודה כדי להגדיר את המצב של מכונת הכביסה, כמו:

"Ok Google, set the carwash to large".

בנוסף, אפשר לשאול שאלות לגבי מכונת הכביסה, כמו:

"Ok Google, what is the washer load?"

5. הוספת לחצנים להחלפת מצב

התכונה action.devices.traits.Toggles מייצגת היבטים של מכשירים שנמצאים במצב נכון או לא נכון, למשל אם מכונת הכביסה במצב טורבו.

עדכון תגובת הסנכרון

בתשובה שלך מסוג SYNC, עליך להוסיף מידע על ה-trait של המכשיר החדש. היא תופיע במערך traits ובאובייקט attributes כפי שמוצג בקטע הקוד הבא.

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',
            }],
          }],
        },
      }],
    },
  };
});

הוספה של פקודות Intent חדשות EXECUTE

ב-Intent EXECUTE, מוסיפים את הפקודה action.devices.commands.SetToggles כפי שמוצג בקטע הקוד הבא.

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

עדכון התשובה QUERY

לסיום, עליך לעדכן את התגובה QUERY כדי לדווח על מצב הטורבו של מכונת הכביסה. מוסיפים את השינויים המעודכנים לפונקציות queryFirebase ו-queryDevice כדי לקבל את מצב המתג כפי שנשמר במסד הנתונים בזמן אמת.

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

עדכון מצב הדוח

לסיום, צריך לעדכן את הפונקציה reportstate כך שתדווח ל-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,
          currentModeSettings: {
            load: snapshot.Modes.load,
          },
          // Add currentToggleSettings
          currentToggleSettings: {
            Turbo: snapshot.Toggles.Turbo,
          },
        },
      },
    },
  },
};

פריסה ב-Firebase

מריצים את הפקודה הבאה כדי לפרוס את הפונקציות המעודכנות:

firebase deploy --only functions

יש ללחוץ על הלחצן רענון ae8d3b25777a5e30.png בממשק המשתמש של האינטרנט כדי להפעיל בקשת סנכרון לאחר השלמת הפריסה.

עכשיו אפשר לתת פקודה כדי להעביר את מכונת הכביסה למצב טורבו על ידי אמירת:

"Ok Google, turn on turbo for the לתת למכונת הכביסה".

אפשר גם לשאול אם מכונת הכביסה נמצאת במצב טורבו:

"Ok Google, is my Wahr in turbo mode?"

6. דיווח על שגיאות וחריגים

טיפול בשגיאות בפעולה של הבית החכם מאפשר לך לדווח למשתמשים על בעיות שגורמות לתגובות EXECUTE ו-QUERY להיכשל. ההתראות יוצרות חוויית משתמש חיובית יותר למשתמשים כשהם מקיימים אינטראקציה עם המכשיר החכם ועם הפעולה שלכם.

בכל פעם שבקשה של EXECUTE או QUERY נכשלת, הפעולה צריכה להחזיר קוד שגיאה. אם, למשל, רציתם להציג הודעת שגיאה כשמשתמש מנסה להפעיל את מכונת הכביסה כשהמכסה פתוח, התשובה של EXECUTE תיראה כמו קטע הקוד הבא:

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

עכשיו, כשמשתמש מבקש להפעיל את מכונת הכביסה, Assistant מגיבה ואומרת:

"המכסה פתוח במכונת הכביסה. יש לסגור אותו ולנסות שוב".

חריגים דומים לשגיאות, אבל הם מציינים מתי התראה משויכת לפקודה, שעלולה לחסום או לא לחסום ביצוע מוצלח. חריג עשוי לספק מידע קשור באמצעות התכונה StatusReport, כמו רמת הטעינה או שינוי במצב מהזמן האחרון. קודי חריגות שאינם חוסמים מוחזרים יחד עם סטטוס SUCCESS, בעוד שקודי חריגים של חסימה מוחזרים עם סטטוס EXCEPTIONS.

דוגמה לתגובה לחריגה נמצאת בקטע הקוד הבא:

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

Assistant מגיבה ואומרת:

"מכונת הכביסה הסתיימה לפעול".

כדי להוסיף דיווח על שגיאות למכונת הכביסה, פותחים את functions/index.js ומוסיפים את ההגדרה של סיווג השגיאה, כפי שמוצג בקטע הקוד הבא:

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

יש לעדכן את תגובת הביצוע כדי להחזיר את קוד השגיאה ואת סטטוס השגיאה:

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

עכשיו Assistant יכולה להודיע למשתמשים על כל קוד שגיאה שדיווחתם עליו. בקטע הבא תוצג דוגמה ספציפית.

7. הוספת אימות משתמש משני

כדאי להטמיע אימות משני של משתמש בפעולה אם יש במכשיר מצבים שצריך לאבטח או שצריך להגביל לקבוצה מסוימת של משתמשים מורשים, למשל עדכון תוכנה או ביטול המעורבות של נעילה.

אפשר להטמיע אימות משתמש משני בכל סוגי המכשירים ובכל המאפיינים של המכשירים, ולקבוע אם אתגר האבטחה מתרחש בכל פעם או שצריך לעמוד בקריטריונים מסוימים.

קיימים שלושה סוגי אתגרים נתמכים:

  • No challenge – בקשה ותגובה שלא נעשה בהן שימוש באתגר אימות (זו התנהגות ברירת המחדל)
  • ackNeeded – אימות משתמש משני שדורש אישור מפורש (כן או לא)
  • pinNeeded – אימות משתמש משני שדורש מספר זיהוי אישי (PIN)

ב-Codelab הזה, צריך להוסיף אתגר ackNeeded לפקודה להפעלת מכונת הכביסה ולפונקציונליות שתחזיר שגיאה אם אתגר האימות המשני נכשל.

פותחים את functions/index.js ומוסיפים הגדרה של סיווג שגיאה שמחזירה את קוד השגיאה ואת סוג האתגר, כפי שהם מופיעים בקטע הקוד הבא:

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

בנוסף, צריך לעדכן את תגובת הביצוע כדי להחזיר את השגיאה challengeNeeded באופן הבא:

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

לסיום, משנים את updateDevice כך שיהיה צורך לקבל אישור מפורש כדי להפעיל או להשבית את מכונת הכביסה.

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

פריסה ב-Firebase

מריצים את הפקודה הבאה כדי לפרוס את הפונקציה המעודכנת:

firebase deploy --only functions

אחרי פריסת הקוד המעודכן, צריך לאשר מילולית את הפעולה כשמבקשים מ-Assistant להפעיל או לכבות את מכונת הכביסה, באופן הבא:

את/ה: "Ok Google, turn on the weather".

Assistant: "האם אתה בטוח שאתה רוצה להפעיל את מכונת הכביסה?"

את/ה: "כן".

אפשר גם לפתוח את יומני Firebase כדי לראות תשובה מפורטת לכל שלב בתהליך האימות המשני של המשתמש.

289dbe48f4bb8106.png

8. מזל טוב

674c4f4392e98c1.png

כל הכבוד! הרחבת את התכונות של הפעולות בבית החכם באמצעות התכונות Modes ו-Toggles, ואבטחת את הביצוע שלהן באמצעות אימות משתמש משני.

מידע נוסף

הנה כמה רעיונות שאפשר ליישם כדי להתעמק בנתונים:

  • הוספת יכולות של ביצוע מקומי למכשירים שלכם.
  • כדי לשנות את מצב המכשיר, צריך להשתמש בסוג אתגר משני אחר לאימות משתמש.
  • יש לעדכן את התגובה QUERY RunCycle לעדכון דינמי.
  • אתם מוזמנים להכיר את הדוגמה הזו ל-GitHub.