การสร้างเว็บแอปพลิเคชันสำหรับการเข้าถึงอุปกรณ์

1. บทนำ

โปรแกรมการเข้าถึงอุปกรณ์มี Smart Device Management API ซึ่งเป็น REST API ไว้ให้นักพัฒนาแอปควบคุมอุปกรณ์ Google Nest จากแอปพลิเคชันของตน ผู้ใช้ต้องให้ความยินยอมแก่บุคคลที่สามในการเข้าถึงอุปกรณ์ Nest ของตน

52f77aa38cda13a6.png

ขั้นตอนสำคัญในการผสานรวมการเข้าถึงอุปกรณ์ให้สำเร็จมี 3 ขั้นตอนดังนี้

  1. การสร้างโปรเจ็กต์ - สร้างโปรเจ็กต์ใน Google Cloud Platform และลงชื่อสมัครใช้เป็นนักพัฒนาซอฟต์แวร์ใน Device Access Console
  2. การลิงก์บัญชี - รับผู้ใช้ผ่านขั้นตอนการลิงก์บัญชีและเรียกข้อมูลรหัสการเข้าถึง แลกเปลี่ยนโค้ดสำหรับโทเค็นเพื่อการเข้าถึง
  3. การควบคุมอุปกรณ์ - สร้างคำขอ Smart Device Management API เพื่อควบคุมอุปกรณ์โดยการส่งคำสั่งพร้อมโทเค็นเพื่อการเข้าถึง

ใน Codelab นี้ เราจะเจาะลึกวิธีการทำงานของการเข้าถึงอุปกรณ์ด้วยการสร้างเว็บแอปพลิเคชันที่จัดการการตรวจสอบสิทธิ์และการเรียกใช้ Smart Device Management API นอกจากนี้ เราจะสำรวจการทำให้พร็อกซีเซิร์ฟเวอร์แบบง่ายโดยใช้ Node.js และ Express เพื่อกำหนดเส้นทางคำขอการเข้าถึงอุปกรณ์

ก่อนที่คุณจะเริ่มต้น เป็นเรื่องดีที่จะทบทวนเทคโนโลยีเว็บทั่วไปที่เราจะใช้ใน Codelab นี้ เช่น การตรวจสอบสิทธิ์ด้วย OAuth 2.0 หรือการสร้างเว็บแอปด้วย Node.js แม้ว่านี่จะไม่ใช่ข้อกำหนดเบื้องต้นก็ตาม

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

  • Node.js 8 ขึ้นไป
  • บัญชี Google กับ Nest Thermostat ที่ลิงก์ไว้

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

  • การตั้งค่าโปรเจ็กต์ Firebase ที่โฮสต์หน้าเว็บแบบคงที่และฟังก์ชันระบบคลาวด์
  • การส่งคำขอเข้าถึงอุปกรณ์ผ่านเว็บแอปพลิเคชันในเบราว์เซอร์
  • การสร้างพร็อกซีเซิร์ฟเวอร์ด้วย Node.js และ Express เพื่อกำหนดเส้นทางคำขอ

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

นักพัฒนาแอปต้องสร้างโปรเจ็กต์ Google Cloud Platform (GCP) เพื่อตั้งค่าการผสานรวมการเข้าถึงอุปกรณ์ ระบบจะใช้รหัสไคลเอ็นต์และรหัสลับไคลเอ็นต์ที่สร้างขึ้นภายในโปรเจ็กต์ GCP เป็นส่วนหนึ่งของโฟลว์ OAuth ระหว่างแอปพลิเคชันของนักพัฒนาซอฟต์แวร์กับ Google Cloud นักพัฒนาแอปจะต้องไปที่ Device Access Console เพื่อสร้างโปรเจ็กต์สำหรับเข้าถึง Smart Device Management API

Google Cloud Platform

ไปที่ Google Cloud Platform คลิกสร้างโปรเจ็กต์ใหม่ แล้วระบุชื่อโปรเจ็กต์ ระบบจะแสดงรหัสโปรเจ็กต์ [GCP-Project-Id] สำหรับ Google Cloud ด้วย โปรดบันทึกรหัสดังกล่าวไว้เนื่องจากเราจะใช้รหัสในระหว่างการตั้งค่า Firebase (เราจะเรียกรหัสนี้ว่า [GCP-Project-Id] ใน Codelab นี้)

585e926b21994ac9.png

ขั้นตอนแรกคือเปิดใช้ไลบรารี API ที่จำเป็นในโปรเจ็กต์ ไปที่ API และ บริการ > ไลบรารี และค้นหา Smart Device Management API คุณต้องเปิดใช้ API นี้เพื่อให้สิทธิ์โปรเจ็กต์ในการส่งคำขอไปยังการเรียก API การเข้าถึงอุปกรณ์

14e7eabc422c7fda.png

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

เมื่อกำหนดค่าหน้าจอคำยินยอม OAuth แล้ว ให้ไปที่ API และ บริการ > ข้อมูลเข้าสู่ระบบ คลิก +สร้างข้อมูลเข้าสู่ระบบ แล้วเลือกรหัสไคลเอ็นต์ OAuth สำหรับประเภทแอปพลิเคชัน ให้เลือกเว็บแอปพลิเคชัน

5de534212d44fce7.png

ตั้งชื่อให้ลูกค้า แล้วคลิกสร้าง เราจะเพิ่มต้นทางของ JavaScript ที่ได้รับอนุญาตและ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตในภายหลัง การทำขั้นตอนนี้ให้เสร็จสิ้นจะแสดง [Client-Id] และ [Client-Secret] ที่เชื่อมโยงกับไคลเอ็นต์ OAuth 2.0 นี้

e6a670da18952f08.png

คอนโซลการเข้าถึงอุปกรณ์

ไปที่คอนโซลการเข้าถึงอุปกรณ์ หากไม่เคยใช้คอนโซลการเข้าถึงอุปกรณ์มาก่อน คุณจะได้รับการยอมรับข้อกำหนดในการให้บริการและค่าธรรมเนียมการลงทะเบียน $5

สร้างโปรเจ็กต์ใหม่แล้วตั้งชื่อ ในหน้าต่างถัดไป ให้ระบุ [Client-Id] ที่ได้รับจาก GCP ในขั้นตอนก่อนหน้า

f8a3f27354bc2625.png

เมื่อเปิดใช้เหตุการณ์และทําตามขั้นตอนการสร้างโปรเจ็กต์ให้เสร็จสิ้น ระบบจะพาคุณไปยังหน้าแรกของโปรเจ็กต์ [Project-Id] ของคุณจะแสดงใต้ชื่อที่คุณตั้งให้โปรเจ็กต์

db7ba33d8b707148.png

โปรดจด [Project-Id] ไว้ เนื่องจากเราจะใช้ข้อมูลนี้เมื่อส่งคำขอไปยัง Smart Device Management API

3. การตั้งค่า Firebase

Firebase ช่วยให้นักพัฒนาซอฟต์แวร์ติดตั้งใช้งานเว็บแอปพลิเคชันได้ง่ายและรวดเร็ว เราจะพัฒนาเว็บแอปพลิเคชันฝั่งไคลเอ็นต์สำหรับการผสานรวมการเข้าถึงอุปกรณ์โดยใช้ Firebase

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

ไปที่คอนโซล Firebase คลิกเพิ่มโปรเจ็กต์ แล้วเลือกโปรเจ็กต์ที่คุณสร้างไว้ในขั้นตอนการสร้างโปรเจ็กต์ การดำเนินการนี้จะสร้างโปรเจ็กต์ Firebase ซึ่งจะลิงก์กับโปรเจ็กต์ GCP ของคุณ [GCP-Project-Id]

เมื่อสร้างโปรเจ็กต์ Firebase เรียบร้อยแล้ว คุณจะเห็นหน้าจอต่อไปนี้

dbb02bbacac093f5.png

ติดตั้งเครื่องมือ Firebase

Firebase มีชุดเครื่องมือ CLI สำหรับสร้างและทำให้แอปใช้งานได้ หากต้องการติดตั้งเครื่องมือเหล่านี้ ให้เปิดหน้าต่างเทอร์มินัลใหม่และเรียกใช้คำสั่งต่อไปนี้ การดำเนินการนี้จะติดตั้งเครื่องมือ Firebase ทั่วโลก

$ npm i -g firebase-tools

หากต้องการยืนยันว่าได้ติดตั้งเครื่องมือ Firebase อย่างถูกต้องแล้ว ให้ตรวจสอบข้อมูลเวอร์ชัน

$ firebase --version

คุณเข้าสู่ระบบเครื่องมือ Firebase CLI ด้วยบัญชี Google ด้วยคำสั่งเข้าสู่ระบบได้

$ firebase login

เริ่มต้นโปรเจ็กต์โฮสติ้ง

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

$ firebase init hosting

Firebase จะถามชุดคำถามเพื่อช่วยคุณเริ่มต้นโปรเจ็กต์โฮสติ้ง ดังนี้

  1. โปรดเลือกตัวเลือก — ใช้โปรเจ็กต์ที่มีอยู่
  2. เลือกโปรเจ็กต์ Firebase เริ่มต้นสำหรับไดเรกทอรีนี้ — เลือก***[GCP-Project-Id]***
  3. คุณต้องการใช้สิ่งใดเป็นไดเรกทอรีสาธารณะของคุณ — สาธารณะ
  4. กำหนดค่าเป็นแอปหน้าเดียวไหม — ใช่
  5. ตั้งค่าบิลด์อัตโนมัติและทำให้ใช้งานได้ด้วย GitHub ไหม — ไม่ใช่

เมื่อเริ่มโปรเจ็กต์แล้ว คุณสามารถทำให้โปรเจ็กต์ใช้งานได้กับ Firebase ด้วยคำสั่งต่อไปนี้

$ firebase deploy

Firebase จะสแกนโปรเจ็กต์และทำให้ไฟล์ที่จำเป็นใช้งานได้ในโฮสติ้งระบบคลาวด์

fe15cf75e985e9a1.png

เมื่อเปิด URL ของโฮสติ้งในเบราว์เซอร์ คุณควรเห็นหน้าเว็บที่เพิ่งนำไปใช้งาน ดังนี้

e40871238c22ebe2.png

เมื่อทราบข้อมูลเบื้องต้นเกี่ยวกับวิธีทำให้หน้าเว็บใช้งานได้ด้วย Firebase แล้ว เรามาเริ่มติดตั้งใช้งานตัวอย่าง Codelab กัน

4. ตัวอย่าง Codelab

คุณโคลนที่เก็บ Codelab ที่โฮสต์บน GitHub ได้โดยใช้คำสั่งด้านล่าง

$ git clone https://github.com/google/device-access-codelab-web-app.git

ในที่เก็บนี้ เราจะให้ตัวอย่างใน 2 โฟลเดอร์แยกกัน โฟลเดอร์ codelab-start มีไฟล์ที่จําเป็นเพื่อช่วยให้คุณเริ่มต้นใช้งานจากจุดปัจจุบันที่ Codelab นี้ โฟลเดอร์ codelab-done มี Codelab เวอร์ชันที่สมบูรณ์ซึ่งมีไคลเอ็นต์และเซิร์ฟเวอร์ Node.js ที่ทำงานได้อย่างสมบูรณ์

เราจะใช้ไฟล์จากโฟลเดอร์ codelab-start ตลอดทั้ง Codelab นี้ แต่หากคุณพบปัญหาเมื่อใดก็ตาม ก็อ้างอิงเวอร์ชัน Codelab เสร็จสิ้นได้ด้วย

ไฟล์ตัวอย่าง Codelab

โครงสร้างไฟล์ของโฟลเดอร์ Codelab-start มีดังนี้

public
├───index.html
├───scripts.js
├───style.css
firebase.json

โฟลเดอร์สาธารณะมีหน้าเว็บแบบคงที่ของแอปพลิเคชัน firebase.json รับหน้าที่กำหนดเส้นทางคำขอเว็บไปยังแอปของเรา ในเวอร์ชัน codelab-done คุณจะเห็นไดเรกทอรี functions ที่มีตรรกะสำหรับพร็อกซีเซิร์ฟเวอร์ (express) ที่จะทำให้ใช้งานได้ในฟังก์ชันของ Google Cloud

ทำให้ตัวอย่าง Codelab ใช้งานได้

คัดลอกไฟล์จาก codelab-start ลงในไดเรกทอรีของโปรเจ็กต์

$ firebase deploy

เมื่อ Firebase ทำให้ใช้งานได้เรียบร้อยแล้ว คุณควรเห็นแอปพลิเคชัน Codelab ดังตัวอย่างต่อไปนี้

e84c1049eb4cca92.png

การเริ่มขั้นตอนการตรวจสอบสิทธิ์จะต้องใช้ข้อมูลเข้าสู่ระบบของพาร์ทเนอร์ ซึ่งเราจะกล่าวถึงในส่วนถัดไป

5. การจัดการ OAuth

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

7ee31f5d9c37f699.png

ระบุ URI การเปลี่ยนเส้นทาง

ขั้นตอนแรกของโฟลว์ OAuth จะต้องมีการส่งชุดพารามิเตอร์ไปยังปลายทาง OAuth 2.0 ของ Google หลังจากได้รับความยินยอมจากผู้ใช้ เซิร์ฟเวอร์ OAuth ของ Google จะส่งคำขอพร้อมรหัสการให้สิทธิ์ไปยัง URI การเปลี่ยนเส้นทาง

อัปเดตค่าคงที่ SERVER_URI (บรรทัดที่ 19) ด้วย URL โฮสติ้งของคุณเองใน scripts.js

const SERVER_URI = "https://[GCP-Project-Id].web.app";

การทำให้แอปใช้งานได้อีกครั้งตามการเปลี่ยนแปลงนี้จะอัปเดต URI การเปลี่ยนเส้นทางที่ใช้สำหรับโปรเจ็กต์ของคุณ

$ firebase deploy

เปิดใช้งาน URI การเปลี่ยนเส้นทาง

เมื่อคุณอัปเดต URI การเปลี่ยนเส้นทางในไฟล์สคริปต์ คุณต้องเพิ่ม URL ดังกล่าวลงในรายการ URI การเปลี่ยนเส้นทางที่อนุญาตสำหรับรหัสไคลเอ็นต์ที่คุณสร้างสำหรับโครงการของคุณ ไปที่หน้าข้อมูลเข้าสู่ระบบใน Google Cloud Platform ซึ่งจะแสดงข้อมูลเข้าสู่ระบบทั้งหมดที่สร้างขึ้นสำหรับโปรเจ็กต์ของคุณ ดังนี้

1a07b624b5e548da.png

ในรายการรหัสไคลเอ็นต์ OAuth 2.0 ให้เลือกรหัสไคลเอ็นต์ที่คุณสร้างในขั้นตอนการสร้างโปรเจ็กต์ เพิ่ม URI การเปลี่ยนเส้นทางของแอปลงในรายการ URI การเปลี่ยนเส้นทางที่ได้รับอนุญาตสำหรับโปรเจ็กต์ของคุณ

6d65b298e1f005e2.png

ลองลงชื่อเข้าใช้

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

78b48906a2dd7c05.png

ปุ่มลงชื่อเข้าใช้จะนำผู้ใช้ไปยังขั้นตอน OAuth สำหรับองค์กรของคุณ โดยเริ่มจากหน้าจอเข้าสู่ระบบไปยังบัญชี Google ของผู้ใช้ เมื่อเข้าสู่ระบบแล้ว ระบบจะขอให้ผู้ใช้ให้สิทธิ์แก่โปรเจ็กต์ในการเข้าถึงอุปกรณ์ Nest ของตน

e9b7887c4ca420.png

เนื่องจากนี่เป็นแอปจำลอง Google จะออกคำเตือนก่อนที่จะทำการเปลี่ยนเส้นทาง

b227d510cb1df073.png

คลิก "ขั้นสูง" จากนั้นเลือก "ไปที่ web.app (ไม่ปลอดภัย)" เพื่อเปลี่ยนเส้นทางไปยังแอปของคุณให้เสร็จสมบูรณ์

673a4fd217e24dad.png

การดำเนินการนี้จะให้รหัส OAuth เป็นส่วนหนึ่งของคำขอ GET ขาเข้า ซึ่งจากนั้นแอปจะแลกเปลี่ยนโทเค็นเพื่อการเข้าถึงและโทเค็นการรีเฟรช

6. ควบคุมอุปกรณ์

แอปตัวอย่างการเข้าถึงอุปกรณ์ใช้การเรียก API ของ REST ของการจัดการอุปกรณ์อัจฉริยะเพื่อควบคุมอุปกรณ์ Google Nest การเรียกเหล่านี้เกี่ยวข้องกับการส่งโทเค็นเพื่อการเข้าถึงในส่วนหัวของคำขอ GET หรือ POST ควบคู่ไปกับเพย์โหลดที่จำเป็นสำหรับคำสั่งบางอย่าง

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

function deviceAccessRequest(method, call, localpath, payload = null) {...}
  • เมธอด — ประเภทของคำขอ HTTP (GET หรือ POST)
  • การเรียก — สตริงที่แสดงถึงการเรียก API ของเรา ซึ่งใช้เพื่อกำหนดเส้นทางการตอบกลับ (listDevices, thermostatMode, temperatureSetpoint)
  • localpath — ปลายทางที่มีการสร้างคำขอ ซึ่งมีรหัสโครงการและรหัสอุปกรณ์ (ต่อท้าย https://smartdevicemanagement.googleapis.com/v1)
  • เพย์โหลด (*) — ข้อมูลเพิ่มเติมที่จำเป็นสำหรับการเรียก API (เช่น ค่าตัวเลขที่แสดงอุณหภูมิสำหรับจุดที่กำหนด)

เราจะสร้างตัวอย่างการควบคุม UI (แสดงรายการอุปกรณ์ โหมดการตั้งค่า ตั้งค่าอุณหภูมิ) เพื่อควบคุม Nest Thermostat ดังนี้

86f8a193aa397421.png

ตัวควบคุม UI เหล่านี้จะเรียกใช้ฟังก์ชันที่เกี่ยวข้อง (listDevices(), postThermostatMode(), postTemperatureSetpoint()) จาก scripts.js เว้นว่างไว้เพื่อนำมาใช้ โดยมีเป้าหมายคือเลือกวิธี/เส้นทางที่ถูกต้องและส่งเพย์โหลดไปยังฟังก์ชัน deviceAccessRequest(...)

แสดงรายการอุปกรณ์

การเรียกการเข้าถึงอุปกรณ์ที่ง่ายที่สุดคือ listDevices โดยใช้คำขอ GET และไม่จำเป็นต้องมีเพย์โหลด ปลายทางต้องมีโครงสร้างโดยใช้ projectId กรอกฟังก์ชัน listDevices() ดังต่อไปนี้

function listDevices() {
  var endpoint = "/enterprises/" + projectId + "/devices";
  deviceAccessRequest('GET', 'listDevices', endpoint);
}

บันทึกการเปลี่ยนแปลงและทำให้โปรเจ็กต์ Firebase ใช้งานได้อีกครั้งด้วยคำสั่งต่อไปนี้

$ firebase deploy

เมื่อใช้งานแอปเวอร์ชันใหม่แล้ว ให้ลองโหลดหน้าเว็บซ้ำและคลิกแสดงรายการอุปกรณ์ การดำเนินการนี้ควรอยู่ในรายการภายใต้การควบคุมอุปกรณ์ ซึ่งคุณควรเห็นรหัสของตัวควบคุมอุณหภูมิของคุณ:

b64a198673ed289f.png

การเลือกอุปกรณ์จากรายการจะอัปเดตช่อง deviceId ในไฟล์ scripts.js สำหรับการควบคุม 2 รายการถัดไป เราจะต้องระบุ deviceId สำหรับอุปกรณ์เฉพาะที่เราต้องการควบคุม

ควบคุมตัวควบคุมอุณหภูมิ

การควบคุม Nest Thermostat ใน Smart Device Management API มีลักษณะ 2 ประการ ThermostatMode และ TemperatureSetpoint ThermostatMode ตั้งค่าโหมดของ Nest Thermostat เป็น 1 ใน 4 โหมดที่แตกต่างกัน ได้แก่ {ปิด, ทำความร้อน, ทำความเย็น, ทำความร้อน} จากนั้นเราจะต้องจัดให้มีโหมดที่เลือกเป็นส่วนหนึ่งของเพย์โหลด

แทนที่ฟังก์ชัน postThermostatMode() ใน scripts.js ด้วยข้อมูลต่อไปนี้

function postThermostatMode() {
  var endpoint = "/enterprises/" + projectId + "/devices/" + deviceId + ":executeCommand";
  var tempMode = id("tempMode").value;
  var payload = {
    "command": "sdm.devices.commands.ThermostatMode.SetMode",
    "params": {
      "mode": tempMode
    }
  };
  deviceAccessRequest('POST', 'thermostatMode', endpoint, payload);
}

ฟังก์ชันถัดไป postTemperatureSetpoint() จะจัดการกับการตั้งค่าอุณหภูมิ (เป็นเซลเซียส) สำหรับ Nest Thermostat คุณตั้งค่าพารามิเตอร์ 2 ตัวในเพย์โหลดได้ คือ heatCelsius และ coolCelsius ทั้งนี้ขึ้นอยู่กับโหมดตัวควบคุมอุณหภูมิที่เลือก

function postTemperatureSetpoint() {
  var endpoint = "/enterprises/" + projectId + "/devices/" + deviceId + ":executeCommand";
  var heatCelsius = parseFloat(id("heatCelsius").value);
  var coolCelsius = parseFloat(id("coolCelsius").value);

  var payload = {
    "command": "",
    "params": {}
  };
  
  if ("HEAT" === id("tempMode").value) {
    payload.command = "sdm.devices.commands.ThermostatTemperatureSetpoint.SetHeat";
    payload.params["heatCelsius"] = heatCelsius;
  }
  else if ("COOL" === id("tempMode").value) {
    payload.command = "sdm.devices.commands.ThermostatTemperatureSetpoint.SetCool";
    payload.params["coolCelsius"] = coolCelsius;
  }
  else if ("HEATCOOL" === id("tempMode").value) {
    payload.command = "sdm.devices.commands.ThermostatTemperatureSetpoint.SetRange";
    payload.params["heatCelsius"] = heatCelsius;
    payload.params["coolCelsius"] = coolCelsius;
  } else {
    console.log("Off and Eco mode don't allow this function");
    return;
  }
  deviceAccessRequest('POST', 'temperatureSetpoint', endpoint, payload);
}

7. เซิร์ฟเวอร์ Node.js (ไม่บังคับ)

ยินดีด้วย คุณได้สร้างเว็บแอปพลิเคชันฝั่งไคลเอ็นต์ที่สามารถส่งคำขอ Smart Device Management API จากเบราว์เซอร์ สำหรับผู้ที่ต้องการสร้างฝั่งเซิร์ฟเวอร์ เราต้องการเริ่มต้นความพยายามอย่างรวดเร็วโดยใช้พร็อกซีเซิร์ฟเวอร์ที่สามารถเปลี่ยนเส้นทางคำขอของคุณจากเบราว์เซอร์

สำหรับพร็อกซีเซิร์ฟเวอร์นี้ เราจะใช้ฟังก์ชันระบบคลาวด์ของ Firebase, Node.js และ Express

เริ่มต้น Cloud Functions

เปิดหน้าต่างเทอร์มินัลใหม่ ไปที่ไดเรกทอรีโครงการและเรียกใช้ดังนี้

$ firebase init functions

Firebase จะถามคำถามคุณเพื่อเริ่มต้นฟังก์ชันระบบคลาวด์ดังนี้

  1. คุณต้องการใช้ภาษาใดในการเขียน Cloud Functions — JavaScript
  2. คุณต้องการใช้ ESLint เพื่อตรวจจับข้อบกพร่องที่อาจเกิดขึ้นและบังคับใช้รูปแบบไหม — ไม่
  3. คุณต้องการติดตั้งทรัพยากร Dependency ด้วย npm ตอนนี้เลยไหม — ใช่

การดำเนินการนี้จะเริ่มต้นโฟลเดอร์ functions ในโปรเจ็กต์ รวมถึงเพื่อติดตั้งทรัพยากร Dependency ที่จำเป็น คุณจะเห็นว่าโฟลเดอร์โปรเจ็กต์มีไดเรกทอรีฟังก์ชัน โดยมีไฟล์ index.js สำหรับระบุฟังก์ชันระบบคลาวด์ package.json เพื่อกำหนดการตั้งค่าและไดเรกทอรี node_modules สำหรับเก็บทรัพยากร Dependency

เราจะใช้ไลบรารี npm 2 รายการเพื่อสร้างฟังก์ชันการทำงานฝั่งเซิร์ฟเวอร์ ได้แก่ express และ xmlhttprequest คุณจะต้องเพิ่มรายการต่อไปนี้ลงในรายการทรัพยากร Dependency ในไฟล์package.json

"xmlhttprequest": "^1.8.0",
"express": "^4.17.0"

จากนั้นการเรียกใช้การติดตั้ง npm จากไดเรกทอรีฟังก์ชันควรติดตั้ง Dependencies สำหรับโปรเจ็กต์ของคุณ:

$ npm install

ในกรณีที่ npm พบปัญหาในการดาวน์โหลดแพ็กเกจ คุณสามารถลองบันทึก xmlhttprequest และแสดงอย่างชัดเจนด้วยคำสั่งต่อไปนี้

$ npm install express xmlhttprequest --save

อัปเกรดเป็นแพ็กเกจ Blaze

เมื่อใช้คำสั่ง firebase deploy คุณจะต้องอัปเกรดเป็นแพ็กเกจ Blaze ซึ่งกำหนดให้คุณเพิ่มวิธีการชำระเงินลงในบัญชี ไปที่ภาพรวมโปรเจ็กต์ > การใช้งานและการเรียกเก็บเงิน และอย่าลืมเลือกแพ็กเกจ Blaze สำหรับโปรเจ็กต์

c6a5e5a21397bef6.png

สร้างเซิร์ฟเวอร์ Express

เซิร์ฟเวอร์ Express ทำตามเฟรมเวิร์กง่ายๆ เพื่อตอบกลับคำขอ GET และ POST ที่เข้ามาใหม่ เราได้สร้างเซิร์ฟเล็ตที่รอรับคำขอ POST ส่งไปยัง URL ปลายทางที่ระบุในเพย์โหลด และตอบกลับด้วยการตอบสนองที่ได้รับจากการโอน

แก้ไขไฟล์ index.js ในไดเรกทอรีฟังก์ชันให้มีลักษณะดังนี้

const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const functions = require('firebase-functions');
const express = require('express');
const http = require('http');

const app = express();
app.use(express.json());


//***** Device Access - Proxy Server *****//

// Serving Get Requests (Not used) 
app.get('*', (request, response) => {
  response.status(200).send("Hello World!");
});
// Serving Post Requests
app.post('*', (request, response) => {
  
  setTimeout(() => {
    // Read the destination address from payload:
    var destination = request.body.address;
    
    // Create a new proxy post request:
    var xhr = new XMLHttpRequest();
    xhr.open('POST', destination);
    
    // Add original headers to proxy request:
    for (var key in request.headers) {
            var value = request.headers[key];
      xhr.setRequestHeader(key, value);
    }
    
    // Add command/parameters to proxy request:
    var newBody = {};
    newBody.command = request.body.command;
    newBody.params = request.body.params;
    
    // Respond to original request with the response coming
    // back from proxy request (to Device Access Endpoint)
    xhr.onload = function () {
      response.status(200).send(xhr.responseText);
    };
    
    // Send the proxy request!
    xhr.send(JSON.stringify(newBody));
  }, 1000);
});

// Export our app to firebase functions:
exports.app = functions.https.onRequest(app);

เพื่อกำหนดเส้นทางคำขอไปยังเซิร์ฟเวอร์ของเรา เราต้องปรับการเขียนใหม่จาก firebase.json ดังนี้

{
  "hosting": {
    "public": "public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [{
        "source": "/proxy**",
        "function": "app"
      },{
        "source": "**",
        "destination": "/index.html"
      }
    ]
  }
}

การดำเนินการนี้จะกำหนดเส้นทาง URL ที่ขึ้นต้นด้วย /proxy ไปยังเซิร์ฟเวอร์ Express และส่วนที่เหลือจะไปที่ index.html

การเรียกใช้ API ของพร็อกซี

เมื่อเราเตรียมเซิร์ฟเวอร์พร้อมแล้ว ลองกำหนด URI พร็อกซีใน scripts.js สำหรับเบราว์เซอร์ของเราให้ส่งคำขอไปยังที่อยู่นี้:

const PROXY_URI = SERVER_URI + "/proxy";

จากนั้นเพิ่มฟังก์ชัน proxyRequest คือ scripts.js ซึ่งมีลายเซ็นเดียวกันกับฟังก์ชัน deviceAccessRequest(...) สำหรับการเรียกการเข้าถึงอุปกรณ์โดยอ้อม

function proxyRequest(method, call, localpath, payload = null) {
    var xhr = new XMLHttpRequest();
    
    // We are doing our post request to our proxy server:
    xhr.open(method, PROXY_URI);
    xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
    xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
    xhr.onload = function () {
      // Response is passed to deviceAccessResponse function:
      deviceAccessResponse(call, xhr.response);
    };
    
    // We are passing the device access endpoint in address field of the payload:
    payload.address = "https://smartdevicemanagement.googleapis.com/v1" + localpath;
    if ('POST' === method && payload)
        xhr.send(JSON.stringify(payload));
    else
        xhr.send();
}

ขั้นตอนสุดท้ายคือการแทนที่การเรียก deviceAccessRequest(...) ด้วยฟังก์ชัน proxyRequest(...) ในฟังก์ชัน postThermostatMode() และ postTemperatureSetpoint() ภายใน scripts.js

เรียกใช้ firebase deploy เพื่ออัปเดตแอป

$ firebase deploy

เพียงเท่านี้คุณก็สามารถใช้พร็อกซีเซิร์ฟเวอร์ Node.js ที่ใช้ Express บน Cloud Functions ได้แล้ว

ให้สิทธิ์ Cloud Function

ขั้นตอนสุดท้ายคือการตรวจสอบสิทธิ์การเข้าถึงสำหรับฟังก์ชันระบบคลาวด์และตรวจสอบว่าแอปพลิเคชันฝั่งไคลเอ็นต์จะเรียกใช้ฟังก์ชันเหล่านั้นได้

จาก Google Cloud Platform ให้ไปที่แท็บ Cloud Functions จากเมนู จากนั้นเลือกฟังก์ชันระบบคลาวด์ ดังนี้

461e9bae74227fc1.png

คลิกสิทธิ์ แล้วคลิกเพิ่มสมาชิก เขียน allUsers ไปยังช่องสมาชิกใหม่ และเลือก Cloud Functions > ผู้เรียกใช้ Cloud Functions เป็นบทบาท การคลิก "บันทึก" จะแสดงข้อความเตือน:

3adb01644217578c.png

การเลือก "อนุญาตการเข้าถึงแบบสาธารณะ" จะทำให้แอปพลิเคชันฝั่งไคลเอ็นต์ของคุณใช้ฟังก์ชันระบบคลาวด์ได้

ยินดีด้วย คุณทำตามขั้นตอนทั้งหมดเรียบร้อยแล้ว ตอนนี้คุณไปที่เว็บแอปและลองใช้ระบบควบคุมอุปกรณ์ผ่านพร็อกซีเซิร์ฟเวอร์ได้แล้ว

ขั้นตอนถัดไป

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

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