1. לפני שמתחילים
בשילובים של ענן לענן נעשה שימוש בסוגים של מכשירים כדי לאפשר ל-Google Assistant לדעת באיזה דקדוק צריך להשתמש עם מכשיר. מאפייני המכשיר מגדירים את היכולות של סוג המכשיר. מכשיר יורש את המצבים של כל מאפיין מכשיר שנוסף לשילוב.
כדי להתאים אישית את הפונקציונליות של המכשירים של המשתמשים, אתם יכולים לקשר כל מאפיין נתמך לסוג המכשיר שבחרתם. אם אתם רוצים להטמיע במאפייני הפעולות מאפיינים מותאמים אישית שלא זמינים כרגע בסכימת המכשיר, תוכלו להשתמש במאפיינים Modes ו-Toggles כדי לשלוט בהגדרות ספציפיות באמצעות שם מותאם אישית שתגדירו.
בנוסף ליכולת הבקרה הבסיסית שמספקים הסוגים והמאפיינים, ל-Smart Home API יש תכונות נוספות לשיפור חוויית המשתמש. תגובות שגיאה מספקות משוב מפורט מהמשתמשים כשכוונות לא מצליחות. אימות משתמש משני מרחיב את התשובות האלה ומוסיף אבטחה נוספת למאפיין המכשיר שבחרתם. שליחת תגובות שגיאה ספציפיות לחסימות שלגרום לאתגרים מ-Assistant יכולה לגרום לכך שאישור נוסף יידרש כדי להשלים פקודה בשילוב בין עננים.
דרישות מוקדמות
- מדריך למפתחים בנושא יצירת שילוב בין עננים
- Codelab בנושא מכונה לכביסה בבית חכם
- מדריך למפתחים בנושא סוגי מכשירים ומאפיינים
מה תפַתחו
בקודלאב הזה פורסים שילוב מובנה מראש של בית חכם עם Firebase, ולאחר מכן מוסבר איך להוסיף מאפיינים לא סטנדרטיים למכונה לכביסה בבית חכם לגבי גודל העומס ומצב הטורבו. בנוסף, תלמדו איך להטמיע דיווח על שגיאות ועל חריגות, ואיך לאכוף אישור מילולי להפעלת מכונת הכביסה באמצעות אימות משתמש משני.
מה תלמדו
- איך מוסיפים את המאפיינים 'מצבים' ו'מתגים' לשילוב
- איך מדווחים על שגיאות ועל חריגות
- איך מפעילים אימות משתמש משני
מה נדרש
- דפדפן אינטרנט, כמו Google Chrome
- מכשיר iOS או Android שבו מותקנת אפליקציית Google Home
- Node.js מגרסה 10.16 ואילך
- חשבון Google
- חשבון לחיוב ב-Google Cloud
2. תחילת העבודה
הפעלת בקרת הפעילות בחשבון
כדי להשתמש ב-Google Assistant, אתם צריכים לשתף עם Google נתוני פעילות מסוימים. הנתונים האלה נחוצים ל-Google Assistant כדי לפעול כראוי, אבל הדרישה לשיתוף נתונים לא ספציפית ל-SDK. כדי לשתף את הנתונים האלה, צריך ליצור חשבון Google, אם עדיין אין לכם חשבון כזה. אפשר להשתמש בכל חשבון Google, לא חייב להיות זה של חשבון הפיתוח.
פותחים את דף בקרת הפעילות בחשבון של חשבון Google שבו רוצים להשתמש עם Assistant.
מוודאים שהמתגים הבאים מופעלים:
- פעילות באינטרנט ובאפליקציות – בנוסף, חשוב לסמן את התיבה הכללת ההיסטוריה והפעילות של Chrome מאתרים, מאפליקציות וממכשירים שמשתמשים בשירותי Google.
- פרטי המכשיר
- תיעוד קול ואודיו
יצירת פרויקט של שילוב בין עננים
- נכנסים ל-Developer Console.
- לוחצים על Create Project, מזינים שם לפרויקט ולוחצים על Create Project.
בחירת השילוב בין עננים
בדף Project Home במסוף הפיתוח, בוחרים באפשרות Add cloud-to-cloud integration בקטע Cloud-to-cloud.
התקנת Firebase CLI
ממשק שורת הפקודה (CLI) של Firebase יאפשר לכם להציג את אפליקציות האינטרנט באופן מקומי ולפרוס את אפליקציית האינטרנט לאירוח ב-Firebase.
כדי להתקין את ה-CLI, מריצים את פקודת ה-npm הבאה מהטרמינל:
npm install -g firebase-tools
כדי לוודא שה-CLI הוטמע כמו שצריך, מריצים את הפקודה הבאה:
firebase --version
נותנים הרשאה ל-Firebase CLI באמצעות חשבון Google:
firebase login
יצירת פרויקט Firebase
- עוברים אל Firebase.
- לוחצים על Create a project ומזינים את שם הפרויקט.
- מסמנים את התיבה של ההסכם ולוחצים על המשך. אם אין תיבת סימון של הסכמה, אפשר לדלג על השלב הזה.
- אחרי שיוצרים את פרויקט Firebase, מחפשים את מזהה הפרויקט. עוברים אל סקירה כללית של הפרויקט ולוחצים על סמל ההגדרות > הגדרות הפרויקט.
- הפרויקט מופיע בכרטיסייה General.
הפעלת HomeGraph API
HomeGraph API מאפשר לאחסן מכשירים ומצבים שלהם ב-Home Graph של המשתמש ולבצע שאילתות לגבי המכשירים האלה. כדי להשתמש ב-API הזה, קודם צריך לפתוח את מסוף Google Cloud ולהפעיל את HomeGraph API.
במסוף Google Cloud, חשוב לבחור את הפרויקט שתואם ל-Actions שלכם <firebase-project-id>.
. לאחר מכן, במסך API Library של HomeGraph API, לוחצים על Enable.
3. הפעלת האפליקציה למתחילים
עכשיו, אחרי שהגדרתם את סביבת הפיתוח, תוכלו לפרוס את פרויקט ההתחלה כדי לוודא שהכול מוגדר כמו שצריך.
קבלת קוד המקור
כדי להוריד את הדוגמה ל-codelab הזה למחשב הפיתוח, לוחצים על הקישור הבא:
...או אפשר לשכפל את מאגר GitHub משורת הפקודה:
git clone https://github.com/google-home/smarthome-traits.git
פותחים את קובץ ה-ZIP שהורדתם.
מידע על הפרויקט
הפרויקט למתחילים מכיל את ספריות המשנה הבאות:
public:
ממשק משתמש חזיתי לצורך בקרה ופיקוח על מצב מכונת הכביסה החכמה.functions:
שירות ענן מיושם במלואו שמנהל את מכונת הכביסה החכמה באמצעות Cloud Functions for Firebase ו-Firebase Realtime Database.
השירות בענן כולל את הפונקציות הבאות ב-index.js
:
fakeauth
: נקודת קצה להרשאה לקישור חשבונותfaketoken
: נקודת קצה של אסימון לקישור חשבוןsmarthome
: נקודת קצה (endpoint) להשלמת כוונה בבית חכםreportstate
: קריאה ל-Home Graph API כשמתרחשים שינויים במצב המכשירrequestsync
: מאפשרת עדכונים של מכשירי המשתמשים בלי צורך לקשר מחדש את החשבון
התחברות ל-Firebase
עוברים לספרייה washer-start
ומגדירים את ה-CLI של Firebase עם פרויקט השילוב:
cd washer-start firebase use <firebase-project-id>
הגדרת פרויקט Firebase
איך מפעילים פרויקט Firebase.
firebase init
בוחרים את התכונות של CLI: Realtime Database, Functions והתכונה Hosting שכוללת את 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
הפעולה הזו תאתחלל את ממשקי ה-API והתכונות הנחוצים לפרויקט.
כשמוצגת בקשה, מאתחלים את Realtime 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
מכיוון שאתם משתמשים בקוד של פרויקט ההתחלה, בוחרים את קובץ ברירת המחדל של כללי האבטחה ומוודאים שלא מחליפים את קובץ הכללים הקיים של מסד הנתונים.
? 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
אם אתם מאתחלים מחדש את הפרויקט, בוחרים באפשרות No כשמתבקשים לאתחל או לשכתב את functions/.gitignore.
? File functions/.gitignore already exists. Overwrite? No
? Do you want to install dependencies with npm now? Yes
לבסוף, מגדירים את הגדרות האירוח כך שישתמשו בספרייה public
בקוד הפרויקט, ומשתמשים בקובץ index.html הקיים. כשתתבקשו להשתמש ב-ESLint, בוחרים באפשרות No.
? 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 הופעל בטעות, יש שתי שיטות להשבתה שלו:
- באמצעות ממשק המשתמש, עוברים לתיקייה
../functions
בפרויקט, בוחרים את הקובץ המוסתר.eslintrc.js
ומוחקים אותו. חשוב לא להתבלבל עם השם הדומה.eslintrc.json
. - באמצעות שורת הפקודה:
cd functions rm .eslintrc.js
פריסה ב-Firebase
עכשיו, אחרי שהוספתם את יחסי התלות והגדרתם את הפרויקט, אתם מוכנים להריץ את האפליקציה בפעם הראשונה.
firebase deploy
זהו הפלט במסוף שאמור להופיע:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<firebase-project-id>/overview Hosting URL: https://<firebase-project-id>.web.app
הפקודה הזו פורסת אפליקציית אינטרנט, יחד עם כמה Cloud Functions for Firebase.
פותחים את כתובת ה-URL של האירוח בדפדפן (https://<firebase-project-id>.web.app
) כדי להציג את אפליקציית האינטרנט. יוצג הממשק הבא:
ממשק המשתמש הזה באינטרנט מייצג פלטפורמה של צד שלישי שדרכה אפשר להציג או לשנות את מצבי המכשיר. כדי להתחיל לאכלס את מסד הנתונים בפרטי המכשיר, לוחצים על עדכון. לא יופיעו שינויים בדף, אבל המצב הנוכחי של מכונת הכביסה יישמר במסד הנתונים.
עכשיו הגיע הזמן לחבר את שירות הענן שפרסמתם ל-Google Assistant באמצעות מסוף הפיתוח.
הגדרת הפרויקט ב-Developer Console
בכרטיסייה Develop, מוסיפים Display Name (שם לתצוגה) לאינטראקציה. השם הזה יופיע באפליקציית Google Home.
בקטע מיתוג האפליקציה, מעלים קובץ png
של סמל האפליקציה בגודל 144 על 144 פיקסלים ובשם
.
כדי להפעיל את קישור החשבון, משתמשים בהגדרות הבאות של קישור החשבון:
Client-ID |
|
סוד לקוח |
|
כתובת אתר להרשאה |
|
כתובת URL לטוקן |
|
בקטע Cloud fulfillment URL, מזינים את כתובת ה-URL של פונקציית הענן שמספקת את הביצוע של כוונת השימוש בבית החכם.
https://us-central1-
לוחצים על Save כדי לשמור את הגדרות הפרויקט, ואז לוחצים על Next: Test כדי להפעיל את הבדיקה בפרויקט.
עכשיו אפשר להתחיל להטמיע את ה-webhooks הנדרשים כדי לקשר את מצב המכשיר ל-Assistant.
קישור ל-Google Assistant
כדי לבדוק את השילוב בין עננים, צריך לקשר את הפרויקט לחשבון Google. כך תוכלו לבדוק את התכונה דרך הממשקים של Google Assistant ואפליקציית Google Home, שמוגדרים להתחברות לאותו חשבון.
- בטלפון, פותחים את ההגדרות של Google Assistant. חשוב לזכור שצריך להתחבר לאותו חשבון שבו אתם מחוברים במסוף.
- עוברים אל Google Assistant > הגדרות > בקרת הבית (בקטע Assistant).
- לוחצים על סמל החיפוש בפינה השמאלית העליונה.
- מחפשים את אפליקציית הבדיקה באמצעות הקידומת [test] כדי למצוא את אפליקציית הבדיקה הספציפית.
- בוחרים את הפריט הזה. לאחר מכן, Google Assistant תאמת את השירות ותשלח בקשה מסוג
SYNC
, שבה היא תבקש מהשירות לספק רשימה של מכשירים למשתמש.
פותחים את אפליקציית Google Home ומוודאים שאפשר לראות את מכונת הכביסה.
מוודאים שאפשר לשלוט במכונה באמצעות פקודות קוליות באפליקציית 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
בהכוונה 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
כדי לקבל את המצב כפי שהוא מאוחסן ב-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,
},
};
};
עדכון סטטוס הדוח
לבסוף, מעדכנים את הפונקציה 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
בסיום הפריסה, עוברים לממשק המשתמש באינטרנט ולוחצים על הלחצן רענון בסרגל הכלים. הפעולה הזו מפעילה בקשה לסנכרון כדי ש-Assistant תקבל את נתוני התשובה המעודכנים של SYNC
.
עכשיו אפשר להשתמש בפקודה כדי להגדיר את המצב של מכונת הכביסה, למשל:
"Ok Google, set the washer load to large"
בנוסף, אפשר לשאול שאלות לגבי מכונת הכביסה, כמו:
"Ok Google, what is the washer load?"
5. הוספת מתגים
המאפיין action.devices.traits.Toggles
מייצג היבטים ספציפיים של מכשיר שיש להם מצב true או false, למשל אם מכונת הכביסה נמצאת במצב טורבו.
עדכון תגובת הסנכרון
בתגובה SYNC
, צריך להוסיף מידע על מאפיין המכשיר החדש. הוא יופיע במערך 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',
}],
}],
},
}],
},
};
});
הוספת פקודות חדשות של כוונת EXECUTE
בהכוונה 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
כדי לקבל את מצב המתג כפי שהוא מאוחסן ב-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,
},
};
};
עדכון סטטוס הדוח
לבסוף, מעדכנים את הפונקציה 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,
currentModeSettings: {
load: snapshot.Modes.load,
},
// Add currentToggleSettings
currentToggleSettings: {
Turbo: snapshot.Toggles.Turbo,
},
},
},
},
},
};
פריסה ב-Firebase
מריצים את הפקודה הבאה כדי לפרוס את הפונקציות המעודכנות:
firebase deploy --only functions
לוחצים על הלחצן Refresh (רענון) בממשק המשתמש באינטרנט כדי להפעיל סנכרון של בקשות אחרי שהפריסה מסתיימת.
עכשיו אפשר להגדיר את מצב הכביסה למצב טורבו באמצעות הפקודה:
"Ok Google, turn on turbo for the washer"
אפשר גם לבדוק אם מכונת הכביסה כבר פועלת במצב טורבו:
"Ok Google, is my washer 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(
updateDevice(execution, device.id)
.then((data) => {
...
})
//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)
בקודלאב הזה, מוסיפים את האתגר 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(
updateDevice(execution, device.id)
.then((data) => {
...
})
.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 washer"
Assistant: "Are you sure you want to turn on the washer?"
אתם: "כן."
אפשר גם לראות תגובה מפורטת לכל שלב בתהליך האימות המשני של המשתמש על ידי פתיחת יומני Firebase.
8. מזל טוב
מעולה! הרחבת התכונות של השילובים בין עננים באמצעות המאפיינים Modes
ו-Toggles
, והגנה על הביצועים שלהם באמצעות אימות משתמש משני.
מידע נוסף
ריכזנו כאן כמה רעיונות שתוכלו ליישם כדי להעמיק את הניתוח:
- הוספת יכולות של ביצוע מקומי למכשירים.
- משתמשים בסוג אחר של אמצעי אימות משני כדי לשנות את מצב המכשיר.
- מעדכנים את התשובה של QUERY למאפיין
RunCycle
כדי שהיא תתעדכן באופן דינמי. - כאן אפשר למצוא דוגמה לכך ב-GitHub.