1. ก่อนเริ่มต้น
การดำเนินการในสมาร์ทโฮมใช้ประเภทอุปกรณ์เพื่อให้ Google Assistant รู้ว่าควรใช้ไวยากรณ์ใดกับอุปกรณ์ ลักษณะของอุปกรณ์เป็นตัวกำหนดความสามารถของอุปกรณ์ อุปกรณ์จะรับช่วงสถานะของลักษณะอุปกรณ์แต่ละรายการที่เพิ่มลงในการดำเนินการ
คุณสามารถเชื่อมต่อลักษณะที่รองรับกับประเภทอุปกรณ์ที่เลือกเพื่อปรับแต่งฟังก์ชันการทำงานของอุปกรณ์ของผู้ใช้ได้ หากคุณต้องการใช้งานลักษณะที่กำหนดเองในการดำเนินการต่างๆ ที่ยังไม่พร้อมใช้งานในสคีมาอุปกรณ์ ลักษณะของ Modes และ Toggles จะอนุญาตการควบคุมการตั้งค่าที่เจาะจงโดยใช้ชื่อที่กำหนดเองที่คุณกำหนด
นอกจากความสามารถในการควบคุมพื้นฐานตามประเภทและลักษณะแล้ว Smart Home API ยังมีฟีเจอร์เพิ่มเติมเพื่อปรับปรุงประสบการณ์ของผู้ใช้ การตอบกลับข้อผิดพลาดจะให้ความคิดเห็นโดยละเอียดแก่ผู้ใช้เมื่อ Intent ไม่สำเร็จ การยืนยันผู้ใช้รองจะขยายคำตอบดังกล่าวและเพิ่มความปลอดภัยให้กับลักษณะของอุปกรณ์ตามที่คุณเลือก การส่งการตอบกลับข้อผิดพลาดที่เจาะจงไปยังบล็อกทดสอบที่ออกโดย Assistant อาจทำให้การดำเนินการในสมาร์ทโฮมของคุณจำเป็นต้องได้รับการให้สิทธิ์เพิ่มเติม จึงจะดำเนินการสั่งได้
ข้อกำหนดเบื้องต้น
- สร้างคู่มือสำหรับนักพัฒนาซอฟต์แวร์เพื่อการดำเนินการสำหรับสมาร์ทโฮม
- Codelab เครื่องซักผ้าสมาร์ทโฮม
- คู่มือนักพัฒนาซอฟต์แวร์ประเภทและลักษณะของอุปกรณ์
สิ่งที่คุณจะสร้าง
ใน Codelab นี้ คุณจะได้ใช้การผสานรวมสมาร์ทโฮมที่สร้างไว้ล่วงหน้ากับ Firebase จากนั้นดูวิธีเพิ่มลักษณะที่ไม่เป็นมาตรฐานลงในเครื่องซักผ้าสมาร์ทโฮมสำหรับขนาดการโหลดและโหมดเทอร์โบ คุณยังใช้การรายงานข้อผิดพลาดและข้อยกเว้น รวมถึงเรียนรู้วิธีบังคับใช้การรับทราบด้วยวาจาเพื่อเปิดเครื่องซักผ้าโดยใช้การยืนยันผู้ใช้รอง
สิ่งที่คุณจะได้เรียนรู้
- วิธีเพิ่มโหมดและการสลับลักษณะลงในแอ็กชัน
- วิธีรายงานข้อผิดพลาดและข้อยกเว้น
- วิธีใช้การยืนยันผู้ใช้รอง
สิ่งที่ต้องมี
- เว็บเบราว์เซอร์ เช่น Google Chrome
- อุปกรณ์ iOS หรือ Android ที่ติดตั้งแอป Google Home
- Node.js เวอร์ชัน 10.16 ขึ้นไป
- บัญชี Google
- บัญชีสำหรับการเรียกเก็บเงินของ Google Cloud
2. เริ่มต้นใช้งาน
เปิดใช้ส่วนควบคุมกิจกรรม
คุณต้องแชร์ข้อมูลกิจกรรมบางอย่างกับ Google จึงจะใช้ Google Assistant ได้ Google Assistant ต้องการให้ข้อมูลนี้ทำงานได้อย่างถูกต้อง แต่ข้อกำหนดในการแชร์ข้อมูลไม่ได้มีไว้เฉพาะใน SDK หากต้องการแชร์ข้อมูลนี้ ให้สร้างบัญชี Google หากยังไม่มีบัญชี คุณจะใช้บัญชี Google ใดก็ได้และไม่จำเป็นต้องเป็นบัญชีนักพัฒนาแอปของคุณ
เปิดหน้าส่วนควบคุมกิจกรรมสำหรับบัญชี Google ที่ต้องการใช้กับ Assistant
ตรวจสอบว่าสวิตช์เปิด/ปิดต่อไปนี้เปิดอยู่
- กิจกรรมบนเว็บและแอป - นอกจากนี้ อย่าลืมเลือกช่องทำเครื่องหมายรวมประวัติการเข้าชมใน Chrome และกิจกรรมจากเว็บไซต์ แอป และอุปกรณ์ที่ใช้บริการต่างๆ ของ Google
- ข้อมูลอุปกรณ์
- กิจกรรมเสียงพูดและเสียง
สร้างโปรเจ็กต์ Actions
- ไปที่คอนโซล Actions on Google Developer
- คลิกโครงการใหม่ ป้อนชื่อโครงการแล้วคลิกสร้างโครงการ
เลือกแอปบ้านอัจฉริยะ
ในหน้าจอภาพรวมในคอนโซลการดำเนินการ ให้เลือกสมาร์ทโฮม
เลือกการ์ดประสบการณ์สมาร์ทโฮม คลิกเริ่มสร้าง แล้วระบบจะนำคุณไปยังคอนโซลของโปรเจ็กต์
ติดตั้ง Firebase CLI
Firebase Command Line Interface (CLI) ช่วยให้คุณแสดงเว็บแอปในเครื่องและใช้งานเว็บแอปในโฮสติ้งของ Firebase ได้
หากต้องการติดตั้ง CLI ให้เรียกใช้คำสั่ง npm ต่อไปนี้จากเทอร์มินัล:
npm install -g firebase-tools
หากต้องการยืนยันว่า CLI ได้รับการติดตั้งอย่างถูกต้อง ให้เรียกใช้คำสั่งต่อไปนี้
firebase --version
ให้สิทธิ์ Firebase CLI ด้วยบัญชี Google โดยการเรียกใช้
firebase login
เปิดใช้ HomeGraph API
HomeGraph API ช่วยให้มีพื้นที่เก็บข้อมูลและค้นหาข้อมูลของอุปกรณ์และสถานะภายใน Home Graph ของผู้ใช้ หากต้องการใช้ API นี้ คุณต้องเปิดคอนโซล Google Cloud และเปิดใช้ HomeGraph API ก่อน
ในคอนโซล Google Cloud ให้ตรวจสอบว่าคุณเลือกโปรเจ็กต์ที่ตรงกับ Actions ของคุณ <project-id>.
จากนั้นคลิกเปิดใช้ในหน้าจอไลบรารี API ของ HomeGraph API
3. เรียกใช้แอปเริ่มต้น
เมื่อตั้งค่าสภาพแวดล้อมการพัฒนาแล้ว คุณสามารถทำให้โปรเจ็กต์เริ่มต้นใช้งานได้เพื่อยืนยันว่าทุกอย่างมีการกำหนดค่าอย่างถูกต้อง
ดูซอร์สโค้ด
คลิกลิงก์ต่อไปนี้เพื่อดาวน์โหลดตัวอย่าง Codelab นี้ในเครื่องการพัฒนาของคุณ
...หรือโคลนที่เก็บ GitHub จากบรรทัดคำสั่งได้
git clone https://github.com/google-home/smarthome-traits.git
คลายการแพคไฟล์ ZIP ที่ดาวน์โหลด
เกี่ยวกับโปรเจ็กต์
โปรเจ็กต์เริ่มต้นมีไดเรกทอรีย่อยต่อไปนี้
public:
UI ฟรอนท์เอนด์ที่ช่วยให้ควบคุมและตรวจสอบสถานะของเครื่องซักผ้าอัจฉริยะได้ง่ายๆfunctions:
บริการระบบคลาวด์ที่ใช้งานอย่างเต็มรูปแบบซึ่งจัดการเครื่องซักผ้าอัจฉริยะด้วย Cloud Functions for Firebase และฐานข้อมูลเรียลไทม์ของ Firebase
Fulfillment ระบบคลาวด์ที่ระบุมีฟังก์ชันต่อไปนี้ใน index.js
fakeauth
: ปลายทางการให้สิทธิ์สำหรับการลิงก์บัญชีfaketoken
: ปลายทางของโทเค็นสำหรับการลิงก์บัญชีsmarthome
: อุปกรณ์ปลายทางสำหรับ Intent ของสมาร์ทโฮมreportstate
: เรียกใช้ Home Graph API เมื่อสถานะของอุปกรณ์มีการเปลี่ยนแปลงrequestsync
: เปิดใช้การอัปเดตอุปกรณ์ของผู้ใช้โดยไม่ต้องลิงก์บัญชีอีกครั้ง
เชื่อมต่อกับ Firebase
ไปที่ไดเรกทอรี washer-start
จากนั้นตั้งค่า Firebase CLI ด้วยโปรเจ็กต์ Actions ดังนี้
cd washer-start firebase use <project-id>
กำหนดค่าโปรเจ็กต์ Firebase
เริ่มต้นโปรเจ็กต์ Firebase
firebase init
เลือกฟีเจอร์ CLI, Realtime Database, ฟังก์ชัน และฟีเจอร์โฮสติ้งที่รวมโฮสติ้งของ 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 และฟีเจอร์ที่จำเป็นสำหรับโปรเจ็กต์ของคุณ
เมื่อมีข้อความแจ้ง ให้เริ่มต้น 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
หากคุณเริ่มต้นโปรเจ็กต์ใหม่ ให้เลือกเขียนทับเมื่อระบบถามว่าคุณต้องการเริ่มต้นหรือเขียนทับฐานของโค้ด
? 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 โดยไม่ได้ตั้งใจ คุณสามารถปิดใช้ได้ 2 วิธี ดังนี้
- ใช้ GUI ให้ไปที่โฟลเดอร์
../functions
ภายใต้โปรเจ็กต์ เลือกไฟล์ที่ซ่อนไว้.eslintrc.js
แล้วลบออก อย่าเข้าใจผิดว่า.eslintrc.json
มีชื่อคล้ายกัน - การใช้บรรทัดคำสั่ง:
cd functions rm .eslintrc.js
ทำให้ใช้งานได้ใน Firebase
เมื่อติดตั้งทรัพยากร Dependency และกำหนดค่าโปรเจ็กต์แล้ว คุณก็พร้อมที่จะเรียกใช้แอปเป็นครั้งแรก
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
) เพื่อดูเว็บแอป โดยคุณจะเห็นอินเทอร์เฟซต่อไปนี้
UI บนเว็บนี้แสดงแพลตฟอร์มของบุคคลที่สามเพื่อดูหรือแก้ไขสถานะของอุปกรณ์ หากต้องการเริ่มสร้างฐานข้อมูลด้วยข้อมูลอุปกรณ์ ให้คลิกอัปเดต คุณจะไม่เห็นการเปลี่ยนแปลงใดๆ ในหน้านั้น แต่ระบบจะเก็บสถานะปัจจุบันของเครื่องซักผ้าไว้ในฐานข้อมูล
ตอนนี้ถึงเวลาเชื่อมต่อบริการระบบคลาวด์ที่คุณทำให้ใช้งานได้กับ Google Assistant โดยใช้คอนโซล Actions แล้ว
กำหนดค่าโปรเจ็กต์คอนโซล Actions
ใต้ภาพรวม > สร้างการดำเนินการ ให้เลือกเพิ่มการดำเนินการ ป้อน URL ของฟังก์ชันระบบคลาวด์ที่ให้ Fulfillment ของ Intent สมาร์ทโฮม แล้วคลิกบันทึก
https://us-central1-<project-id>.cloudfunctions.net/smarthome
ในแท็บพัฒนา > การเรียกใช้ ให้เพิ่มชื่อที่แสดงสำหรับการดำเนินการ แล้วคลิกบันทึก ชื่อนี้จะปรากฏในแอป Google Home
หากต้องการเปิดใช้การลิงก์บัญชี ให้เลือกตัวเลือกพัฒนา > การลิงก์บัญชี ในการนำทางด้านซ้าย ใช้การตั้งค่าการลิงก์บัญชีเหล่านี้
Client-ID |
|
รหัสลับไคลเอ็นต์ |
|
URL สำหรับการอนุญาต |
|
URL โทเค็น |
|
คลิกบันทึกเพื่อบันทึกการกำหนดค่าการลิงก์บัญชี แล้วคลิกทดสอบเพื่อเปิดใช้การทดสอบในโปรเจ็กต์
ระบบจะเปลี่ยนเส้นทางคุณไปยังเครื่องมือจำลอง หากคุณไม่เห็น "เปิดใช้การทดสอบเลย" ให้คลิกรีเซ็ตการทดสอบเพื่อยืนยันว่าการทดสอบเปิดใช้อยู่
ลิงก์กับ Google Assistant
คุณต้องลิงก์โปรเจ็กต์กับบัญชี Google เพื่อทดสอบการดำเนินการสำหรับสมาร์ทโฮม การดำเนินการนี้จะทำให้ทำการทดสอบผ่านแพลตฟอร์มของ Google Assistant และแอป Google Home ที่ลงชื่อเข้าใช้บัญชีเดียวกัน
- เปิดการตั้งค่า Google Assistant ในโทรศัพท์ โปรดทราบว่าคุณควรลงชื่อเข้าสู่ระบบด้วยบัญชีเดียวกับในคอนโซล
- ไปที่ Google Assistant > การตั้งค่า > ระบบควบคุมอุปกรณ์ในบ้าน (ในส่วน Assistant)
- คลิกไอคอนค้นหาที่ด้านขวาบน
- ค้นหาแอปทดสอบโดยใช้คำนำหน้า [test] เพื่อค้นหาแอปทดสอบที่คุณต้องการ
- เลือกรายการนั้น จากนั้น Google Assistant จะตรวจสอบสิทธิ์กับบริการและส่งคำขอ
SYNC
เพื่อขอให้บริการของคุณระบุรายการอุปกรณ์ให้กับผู้ใช้
เปิดแอป Google Home แล้วตรวจสอบว่าเห็นอุปกรณ์เครื่องซักผ้า
ยืนยันว่าคุณควบคุมเครื่องซักผ้าได้โดยใช้คำสั่งเสียงในแอป Google Home และคุณควรจะเห็นสถานะของอุปกรณ์ใน UI เว็บฟรอนท์เอนด์ของ Cloud Fulfillment ด้วย
ตอนนี้คุณมีเครื่องซักผ้าพื้นฐานแล้ว คุณจะปรับแต่งโหมดที่ใช้ได้ในอุปกรณ์
4. เพิ่มโหมด
ลักษณะของ action.devices.traits.Modes
ช่วยให้อุปกรณ์มีการตั้งค่าจำนวนมากขึ้นสำหรับแต่ละโหมด ซึ่งจะตั้งค่าได้ทีละ 1 รายการเท่านั้น คุณจะเพิ่มโหมดให้กับเครื่องซักผ้าเพื่อกำหนดขนาดของเครื่องซักผ้าได้ ได้แก่ เล็ก กลาง หรือใหญ่
อัปเดตการตอบสนองการซิงค์
คุณต้องเพิ่มข้อมูลเกี่ยวกับลักษณะใหม่ลงในคำตอบ 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,
}],
},
}],
},
};
});
เพิ่มคำสั่ง Intent EXECUTE ใหม่
ใน 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
เพื่อรับสถานะที่จัดเก็บไว้ใน 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
เพื่อรายงานการตั้งค่าการโหลดปัจจุบันของเครื่องซักผ้าไปยัง Home Graph
index.js
const requestBody = {
requestId: 'ff36a3cc', /* Any unique ID */
agentUserId: USER_ID,
payload: {
devices: {
states: {
/* Report the current state of your washer */
[context.params.deviceId]: {
on: snapshot.OnOff.on,
isPaused: snapshot.StartStop.isPaused,
isRunning: snapshot.StartStop.isRunning,
// Add currentModeSettings
currentModeSettings: {
load: snapshot.Modes.load,
},
},
},
},
},
};
ทำให้ใช้งานได้ใน Firebase
เรียกใช้คำสั่งต่อไปนี้เพื่อทำให้การดำเนินการที่อัปเดตใช้งานได้
firebase deploy --only functions
หลังจากทำให้ใช้งานได้เรียบร้อยแล้ว ให้ไปที่ UI ของเว็บแล้วคลิกปุ่มรีเฟรช ในแถบเครื่องมือ ซึ่งจะทริกเกอร์การซิงค์คำขอเพื่อให้ Assistant ได้รับข้อมูลการตอบกลับ SYNC
ที่อัปเดต
คุณสามารถใช้คำสั่งเพื่อตั้งค่าโหมดของเครื่องซักผ้าได้ เช่น
"Ok Google ตั้งค่าเครื่องซักผ้าเป็นก้อนใหญ่"
นอกจากนั้น คุณยังถามคําถามเกี่ยวกับเครื่องซักผ้าได้ เช่น
"Ok Google เครื่องซักผ้าคืออะไร"
5. เพิ่มปุ่มเปิด/ปิด
ลักษณะของ action.devices.traits.Toggles
แสดงถึงลักษณะที่มีชื่อของอุปกรณ์ที่มีสถานะจริงหรือเท็จ เช่น เครื่องซักผ้าอยู่ในโหมดเทอร์โบหรือไม่
อัปเดตการตอบสนองการซิงค์
ในการตอบกลับ 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',
}],
}],
},
}],
},
};
});
เพิ่มคำสั่ง 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
เพื่อรับสถานะการเปิด/ปิดที่จัดเก็บไว้ใน 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
เพื่อรายงานไปยัง 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
คลิกปุ่มรีเฟรช ใน UI เว็บเพื่อทริกเกอร์การซิงค์คำขอหลังจากการติดตั้งใช้งานเสร็จสมบูรณ์แล้ว
คุณออกคำสั่งให้ตั้งเครื่องซักผ้าเป็นโหมดเทอร์โบได้เลย โดยพูดว่า
"Ok Google เปิดเทอร์โบสำหรับเครื่องซักผ้า"
หรือถามว่าเครื่องซักผ้าอยู่ในโหมดเทอร์โบหรือยังได้โดยถามว่า
"Ok Google เครื่องซักผ้าของฉันอยู่ในโหมดเทอร์โบหรือเปล่า"
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. เพิ่มการยืนยันผู้ใช้รอง
คุณควรใช้การยืนยันผู้ใช้รองในการดำเนินการ หากอุปกรณ์มีโหมดที่ต้องมีความปลอดภัย หรือควรจำกัดไว้เฉพาะกลุ่มผู้ใช้ที่ได้รับอนุญาตเท่านั้น เช่น การอัปเดตซอฟต์แวร์หรือการยกเลิกการเชื่อมต่อ
คุณสามารถใช้การยืนยันผู้ใช้รองในอุปกรณ์ทุกประเภทและลักษณะต่างๆ ได้ โดยสามารถปรับแต่งได้ว่าจำเป็นต้องมีคำถามเพื่อความปลอดภัยทุกครั้งหรือต้องมีคุณสมบัติตรงตามเกณฑ์ที่เฉพาะเจาะจงหรือไม่
มีชาเลนจ์ที่รองรับ 3 ประเภท ดังนี้
No
challenge
- คำขอและคำตอบที่ไม่ใช้คำถามเพื่อตรวจสอบสิทธิ์ (นี่คือลักษณะการทำงานเริ่มต้น)ackNeeded
- การยืนยันผู้ใช้ครั้งที่ 2 ที่ต้องรับทราบอย่างชัดแจ้ง (ใช่หรือไม่ใช่)pinNeeded
- การยืนยันผู้ใช้สำรองที่ต้องใช้หมายเลขประจำตัวส่วนบุคคล (PIN)
สำหรับ Codelab นี้ ให้เพิ่มคำถาม ackNeeded
ในคำสั่งสำหรับการเปิดเครื่องซักผ้าและฟังก์ชันเพื่อส่งกลับข้อผิดพลาดในกรณีที่การยืนยันครั้งที่ 2 ไม่สำเร็จ
เปิด 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 เปิดเครื่องซักผ้า"
Assistant: "แน่ใจไหมว่าจะเปิดเครื่องซักผ้า"
คุณ: "อยาก"
นอกจากนี้ คุณยังดูคำตอบโดยละเอียดสำหรับแต่ละขั้นตอนของขั้นตอนการยืนยันผู้ใช้รองได้โดยเปิดบันทึก Firebase
8. ขอแสดงความยินดี
ยินดีด้วย คุณได้ขยายฟีเจอร์ของการดำเนินการในสมาร์ทโฮมผ่านลักษณะของ Modes
และ Toggles
รวมถึงรักษาความปลอดภัยของการดำเนินการผ่านการยืนยันผู้ใช้รอง
ดูข้อมูลเพิ่มเติม
แนวคิดบางส่วนที่คุณสามารถนำไปใช้เพื่อเจาะลึกมากขึ้นมีดังนี้
- เพิ่มความสามารถในการดำเนินการภายในเครื่องให้กับอุปกรณ์
- ใช้ประเภทการยืนยันผู้ใช้สำรองประเภทอื่นเพื่อแก้ไขสถานะอุปกรณ์
- อัปเดตการตอบกลับลักษณะ QUERY ของลักษณะ
RunCycle
เพื่ออัปเดตแบบไดนามิก - ดูตัวอย่างนี้ใน GitHub