ปรับปรุงและรักษาความปลอดภัยให้กับการดําเนินการในบ้านอัจฉริยะ

1. ก่อนเริ่มต้น

การดำเนินการในสมาร์ทโฮมใช้ประเภทอุปกรณ์เพื่อให้ Google Assistant รู้ว่าควรใช้ไวยากรณ์ใดกับอุปกรณ์ ลักษณะของอุปกรณ์เป็นตัวกำหนดความสามารถของอุปกรณ์ อุปกรณ์จะรับช่วงสถานะของลักษณะอุปกรณ์แต่ละรายการที่เพิ่มลงในการดำเนินการ

dc8dce0dea87cd5c.png

คุณสามารถเชื่อมต่อลักษณะที่รองรับกับประเภทอุปกรณ์ที่เลือกเพื่อปรับแต่งฟังก์ชันการทำงานของอุปกรณ์ของผู้ใช้ได้ หากคุณต้องการใช้งานลักษณะที่กำหนดเองในการดำเนินการต่างๆ ที่ยังไม่พร้อมใช้งานในสคีมาอุปกรณ์ ลักษณะของ Modes และ Toggles จะอนุญาตการควบคุมการตั้งค่าที่เจาะจงโดยใช้ชื่อที่กำหนดเองที่คุณกำหนด

นอกจากความสามารถในการควบคุมพื้นฐานตามประเภทและลักษณะแล้ว Smart Home API ยังมีฟีเจอร์เพิ่มเติมเพื่อปรับปรุงประสบการณ์ของผู้ใช้ การตอบกลับข้อผิดพลาดจะให้ความคิดเห็นโดยละเอียดแก่ผู้ใช้เมื่อ Intent ไม่สำเร็จ การยืนยันผู้ใช้รองจะขยายคำตอบดังกล่าวและเพิ่มความปลอดภัยให้กับลักษณะของอุปกรณ์ตามที่คุณเลือก การส่งการตอบกลับข้อผิดพลาดที่เจาะจงไปยังบล็อกทดสอบที่ออกโดย Assistant อาจทำให้การดำเนินการในสมาร์ทโฮมของคุณจำเป็นต้องได้รับการให้สิทธิ์เพิ่มเติม จึงจะดำเนินการสั่งได้

ข้อกำหนดเบื้องต้น

สิ่งที่คุณจะสร้าง

ใน Codelab นี้ คุณจะได้ใช้การผสานรวมสมาร์ทโฮมที่สร้างไว้ล่วงหน้ากับ Firebase จากนั้นดูวิธีเพิ่มลักษณะที่ไม่เป็นมาตรฐานลงในเครื่องซักผ้าสมาร์ทโฮมสำหรับขนาดการโหลดและโหมดเทอร์โบ คุณยังใช้การรายงานข้อผิดพลาดและข้อยกเว้น รวมถึงเรียนรู้วิธีบังคับใช้การรับทราบด้วยวาจาเพื่อเปิดเครื่องซักผ้าโดยใช้การยืนยันผู้ใช้รอง

สิ่งที่คุณจะได้เรียนรู้

  • วิธีเพิ่มโหมดและการสลับลักษณะลงในแอ็กชัน
  • วิธีรายงานข้อผิดพลาดและข้อยกเว้น
  • วิธีใช้การยืนยันผู้ใช้รอง

สิ่งที่ต้องมี

2. เริ่มต้นใช้งาน

เปิดใช้ส่วนควบคุมกิจกรรม

คุณต้องแชร์ข้อมูลกิจกรรมบางอย่างกับ Google จึงจะใช้ Google Assistant ได้ Google Assistant ต้องการให้ข้อมูลนี้ทำงานได้อย่างถูกต้อง แต่ข้อกำหนดในการแชร์ข้อมูลไม่ได้มีไว้เฉพาะใน SDK หากต้องการแชร์ข้อมูลนี้ ให้สร้างบัญชี Google หากยังไม่มีบัญชี คุณจะใช้บัญชี Google ใดก็ได้และไม่จำเป็นต้องเป็นบัญชีนักพัฒนาแอปของคุณ

เปิดหน้าส่วนควบคุมกิจกรรมสำหรับบัญชี Google ที่ต้องการใช้กับ Assistant

ตรวจสอบว่าสวิตช์เปิด/ปิดต่อไปนี้เปิดอยู่

  • กิจกรรมบนเว็บและแอป - นอกจากนี้ อย่าลืมเลือกช่องทำเครื่องหมายรวมประวัติการเข้าชมใน Chrome และกิจกรรมจากเว็บไซต์ แอป และอุปกรณ์ที่ใช้บริการต่างๆ ของ Google
  • ข้อมูลอุปกรณ์
  • กิจกรรมเสียงพูดและเสียง

สร้างโปรเจ็กต์ Actions

  1. ไปที่คอนโซล Actions on Google Developer
  2. คลิกโครงการใหม่ ป้อนชื่อโครงการแล้วคลิกสร้างโครงการ

3d6b68ca79afd54c.png

เลือกแอปบ้านอัจฉริยะ

ในหน้าจอภาพรวมในคอนโซลการดำเนินการ ให้เลือกสมาร์ทโฮม

2fa4988f44f8914b.png

เลือกการ์ดประสบการณ์สมาร์ทโฮม คลิกเริ่มสร้าง แล้วระบบจะนำคุณไปยังคอนโซลของโปรเจ็กต์

ติดตั้ง 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

ee198858a6eac112.png

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 วิธี ดังนี้

  1. ใช้ GUI ให้ไปที่โฟลเดอร์ ../functions ภายใต้โปรเจ็กต์ เลือกไฟล์ที่ซ่อนไว้ .eslintrc.js แล้วลบออก อย่าเข้าใจผิดว่า .eslintrc.json มีชื่อคล้ายกัน
  2. การใช้บรรทัดคำสั่ง:
    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) เพื่อดูเว็บแอป โดยคุณจะเห็นอินเทอร์เฟซต่อไปนี้

5845443e94705557.png

UI บนเว็บนี้แสดงแพลตฟอร์มของบุคคลที่สามเพื่อดูหรือแก้ไขสถานะของอุปกรณ์ หากต้องการเริ่มสร้างฐานข้อมูลด้วยข้อมูลอุปกรณ์ ให้คลิกอัปเดต คุณจะไม่เห็นการเปลี่ยนแปลงใดๆ ในหน้านั้น แต่ระบบจะเก็บสถานะปัจจุบันของเครื่องซักผ้าไว้ในฐานข้อมูล

ตอนนี้ถึงเวลาเชื่อมต่อบริการระบบคลาวด์ที่คุณทำให้ใช้งานได้กับ Google Assistant โดยใช้คอนโซล Actions แล้ว

กำหนดค่าโปรเจ็กต์คอนโซล Actions

ใต้ภาพรวม > สร้างการดำเนินการ ให้เลือกเพิ่มการดำเนินการ ป้อน URL ของฟังก์ชันระบบคลาวด์ที่ให้ Fulfillment ของ Intent สมาร์ทโฮม แล้วคลิกบันทึก

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

9d7b223427f587ca.png

ในแท็บพัฒนา > การเรียกใช้ ให้เพิ่มชื่อที่แสดงสำหรับการดำเนินการ แล้วคลิกบันทึก ชื่อนี้จะปรากฏในแอป Google Home

774d0c40c351c7da.png

a8c4673eb11d76ee.png

หากต้องการเปิดใช้การลิงก์บัญชี ให้เลือกตัวเลือกพัฒนา > การลิงก์บัญชี ในการนำทางด้านซ้าย ใช้การตั้งค่าการลิงก์บัญชีเหล่านี้

Client-ID

ABC123

รหัสลับไคลเอ็นต์

DEF456

URL สำหรับการอนุญาต

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

URL โทเค็น

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

9730d20b90bcc038.png

คลิกบันทึกเพื่อบันทึกการกำหนดค่าการลิงก์บัญชี แล้วคลิกทดสอบเพื่อเปิดใช้การทดสอบในโปรเจ็กต์

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 และคุณควรจะเห็นสถานะของอุปกรณ์ใน 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 ของเว็บแล้วคลิกปุ่มรีเฟรช ae8d3b25777a5e30.png ในแถบเครื่องมือ ซึ่งจะทริกเกอร์การซิงค์คำขอเพื่อให้ Assistant ได้รับข้อมูลการตอบกลับ SYNC ที่อัปเดต

bf4f6a866160a982.png

คุณสามารถใช้คำสั่งเพื่อตั้งค่าโหมดของเครื่องซักผ้าได้ เช่น

"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

คลิกปุ่มรีเฟรช ae8d3b25777a5e30.png ใน 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

289dbe48f4bb8106.png

8. ขอแสดงความยินดี

674c4f4392e98c1.png

ยินดีด้วย คุณได้ขยายฟีเจอร์ของการดำเนินการในสมาร์ทโฮมผ่านลักษณะของ Modes และ Toggles รวมถึงรักษาความปลอดภัยของการดำเนินการผ่านการยืนยันผู้ใช้รอง

ดูข้อมูลเพิ่มเติม

แนวคิดบางส่วนที่คุณสามารถนำไปใช้เพื่อเจาะลึกมากขึ้นมีดังนี้

  • เพิ่มความสามารถในการดำเนินการภายในเครื่องให้กับอุปกรณ์
  • ใช้ประเภทการยืนยันผู้ใช้สำรองประเภทอื่นเพื่อแก้ไขสถานะอุปกรณ์
  • อัปเดตการตอบกลับลักษณะ QUERY ของลักษณะ RunCycle เพื่ออัปเดตแบบไดนามิก
  • ดูตัวอย่างนี้ใน GitHub