หากต้องการรองรับการดำเนินการในเครื่อง คุณต้องสร้างแอปเพื่อจัดการ Intent ของสมาร์ทโฮมต่อไปนี้
IDENTIFY: รองรับการค้นหาอุปกรณ์อัจฉริยะที่ควบคุมได้ภายในเครื่อง เครื่องจัดการ Intent จะดึงข้อมูลที่อุปกรณ์อัจฉริยะแสดงผลระหว่างการค้นพบและส่งข้อมูลนี้ในการตอบกลับไปยัง GoogleEXECUTE: รองรับการดำเนินการตามคำสั่งQUERY: รองรับการค้นหาสถานะอุปกรณ์REACHABLE_DEVICES: (ไม่บังคับ) รองรับการค้นหาอุปกรณ์ปลายทางที่ควบคุมได้ในเครื่องซึ่งอยู่หลังอุปกรณ์ฮับ (หรือบริดจ์)
แอปนี้ทำงานบนอุปกรณ์ Google Home หรือ Google Nest ของผู้ใช้และเชื่อมต่ออุปกรณ์อัจฉริยะกับ Assistant คุณสร้างแอปโดยใช้ TypeScript (แนะนำ) หรือ JavaScript ก็ได้
เราขอแนะนำให้ใช้ TypeScript เนื่องจากคุณสามารถใช้ประโยชน์จากการเชื่อมโยงเพื่อตรวจสอบแบบคงที่ว่าข้อมูลที่แอปแสดงผลตรงกับประเภทที่แพลตฟอร์มคาดหวัง
ดูรายละเอียดเพิ่มเติมเกี่ยวกับ API ได้ที่เอกสารอ้างอิง API ของ Local Home SDK
ข้อมูลโค้ดต่อไปนี้แสดงวิธีเริ่มต้นแอปการดำเนินการภายในและแนบแฮนเดิล
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
import App = smarthome.App; const localHomeApp: App = new App("1.0.0"); localHomeApp .onIdentify(identifyHandler) .onReachableDevices(reachableDevicesHandler) .onExecute(executeHandler) .listen() .then(() => { console.log("Ready"); });
สร้างโปรเจ็กต์
หากต้องการติดตั้งใช้งานแอปการดำเนินการในพื้นที่ คุณต้องสร้างแพ็กเกจ JavaScript สำหรับโค้ดและทรัพยากร Dependency ทั้งหมด
ใช้ตัวเริ่มต้นโปรเจ็กต์ของแอปการดำเนินการในพื้นที่เพื่อเริ่มต้นโครงสร้างโปรเจ็กต์ที่เหมาะสมด้วยการกำหนดค่า Bundler ที่คุณต้องการ
เทมเพลตโปรเจ็กต์
หากต้องการเลือกการกำหนดค่า Bundler ให้เรียกใช้คำสั่ง npm init ดังที่แสดงในตัวอย่างต่อไปนี้
TypeScript ที่ไม่มีการกำหนดค่า Bundler
npm init @google/local-home-app project-directory/ --bundler none
โครงสร้างโปรเจ็กต์
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
แทนที่ project-directory ด้วยไดเรกทอรีใหม่ที่จะมีโปรเจ็กต์แอป Fulfillment ในพื้นที่
การกำหนดค่า Bundler ของ webpack ด้วย TypeScript:
npm init @google/local-home-app project-directory/ --bundler webpack
โครงสร้างโปรเจ็กต์
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── webpack.config.web.js ├── webpack.config.node.js └── serve.js
แทนที่ project-directory ด้วยไดเรกทอรีใหม่ที่จะมีโปรเจ็กต์แอป Fulfillment ในพื้นที่
การกำหนดค่า Bundler ของ TypeScript ด้วย Rollup
npm init @google/local-home-app project-directory/ --bundler rollup
โครงสร้างโปรเจ็กต์
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json ├── rollup.config.js └── serve.js
แทนที่ project-directory ด้วยไดเรกทอรีใหม่ที่จะมีโปรเจ็กต์แอป Fulfillment ในพื้นที่
การกำหนดค่า Bundler ของ TypeScript ด้วย Parcel
npm init @google/local-home-app project-directory/ --bundler parcel
โครงสร้างโปรเจ็กต์
project-directory/ ├── node_modules/ ├── package.json ├── .gitignore ├── index.ts ├── test.ts ├── tsconfig.json ├── tslint.json └── serve.js
แทนที่ project-directory ด้วยไดเรกทอรีใหม่ที่จะมีโปรเจ็กต์แอปการดำเนินการในพื้นที่
ทำงานทั่วไปในระดับโปรเจ็กต์
โปรเจ็กต์ที่สร้างขึ้นรองรับสคริปต์ npm ต่อไปนี้
cd project-directory/ npm run build
สคริปต์นี้จะคอมไพล์แหล่งที่มาของ TypeScript และรวมแอปของคุณเข้ากับทรัพยากร Dependency สำหรับสภาพแวดล้อมรันไทม์ของ Chrome ในไดเรกทอรีย่อย dist/web และสภาพแวดล้อมรันไทม์ของ Node.js ในไดเรกทอรีย่อย dist/node
cd project-directory/ npm run lint npm run compile npm test
สคริปต์นี้จะตรวจสอบไวยากรณ์ของโค้ด TypeScript, คอมไพล์โค้ดโดยไม่สร้างเอาต์พุตใดๆ ในไดเรกทอรีย่อย dist/ และเรียกใช้การทดสอบอัตโนมัติจาก test.ts
cd project-directory/ npm run start
ในระหว่างการพัฒนา สคริปต์นี้จะแสดง App Bundle สำหรับสภาพแวดล้อมรันไทม์ของ Chrome และ Node.js ในเครื่อง
ใช้แฮนเดิล IDENTIFY
ระบบจะทริกเกอร์แฮนเดิล IDENTIFY เมื่ออุปกรณ์ Google Home หรืออุปกรณ์ Google Nest รีบูตและเห็นอุปกรณ์ในพื้นที่ที่ไม่ได้รับการยืนยัน (รวมถึงอุปกรณ์ปลายทางที่เชื่อมต่อกับฮับ) แพลตฟอร์ม Local Home จะสแกนหาอุปกรณ์ในพื้นที่โดยใช้ข้อมูลการกำหนดค่าการสแกนที่คุณระบุไว้ก่อนหน้านี้ และเรียกใช้แฮนเดิล IDENTIFY พร้อมผลการสแกน
IdentifyRequest
จากแพลตฟอร์ม Local Home มีข้อมูลการสแกนของอินสแตนซ์
LocalIdentifiedDevice ระบบจะแสดงข้อมูล device เพียงรายการเดียว โดยอิงตามการกำหนดค่าการสแกนที่ค้นพบอุปกรณ์
หากผลการสแกนตรงกับอุปกรณ์ของคุณ ตัวแฮนเดิล IDENTIFY ควรแสดงผลออบเจ็กต์ IdentifyResponsePayload ซึ่งรวมถึงออบเจ็กต์ device ที่มีข้อมูลเมตาของสมาร์ทโฮม (เช่น ประเภท ลักษณะ และสถานะรายงาน)
Google จะสร้างการเชื่อมโยงอุปกรณ์หาก verificationId จากการตอบกลับ IDENTIFY ตรงกับค่า otherDeviceIds ค่าใดค่าหนึ่งที่แสดงผลโดยการตอบกลับ SYNC
ตัวอย่าง
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างแฮนเดอร์ IDENTIFY สำหรับการผสานรวมอุปกรณ์แบบสแตนด์อโลนและฮับตามลำดับ
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const verificationId = "local-device-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: device.id || "", verificationId, // Must match otherDeviceIds in SYNC response }, }, }; return response; };
const identifyHandler = (request: IntentFlow.IdentifyRequest): IntentFlow.IdentifyResponse => { // Obtain scan data from protocol defined in your scan config const device = request.inputs[0].payload.device; if (device.udpScanData === undefined) { throw Error("Missing discovery response"); } const scanData = device.udpScanData.data; // Decode scan data to obtain metadata about local device const proxyDeviceId = "local-hub-id"; // Return a response const response: IntentFlow.IdentifyResponse = { intent: Intents.IDENTIFY, requestId: request.requestId, payload: { device: { id: proxyDeviceId, isProxy: true, // Device can control other local devices isLocalOnly: true, // Device not present in `SYNC` response }, }, }; return response; };
ระบุอุปกรณ์ที่อยู่หลังฮับ
หาก Google ระบุอุปกรณ์ฮับได้ ระบบจะถือว่าฮับเป็นสื่อกลางในการเชื่อมต่อกับอุปกรณ์ปลายทางที่เชื่อมต่อกับฮับ และพยายามยืนยันอุปกรณ์ปลายทางเหล่านั้น
หากต้องการให้ Google ยืนยันว่ามีอุปกรณ์ฮับอยู่ ให้ทำตามวิธีการต่อไปนี้สำหรับแฮนเดิล IDENTIFY
- หากการตอบกลับ
SYNCรายงานรหัสของอุปกรณ์ปลายทางในพื้นที่ที่เชื่อมต่อกับฮับ ให้ตั้งค่าisProxyเป็นtrueในIdentifyResponsePayload - หากการตอบกลับ
SYNCไม่รายงานอุปกรณ์ฮับ ให้ตั้งค่าisLocalOnlyเป็นtrueในIdentifyResponsePayload - ช่อง
device.idมีรหัสอุปกรณ์ในเครื่องสำหรับอุปกรณ์ฮับเอง
ใช้แฮนเดิล REACHABLE_DEVICES (การผสานรวมฮับเท่านั้น)
Google จะส่ง Intent REACHABLE_DEVICES เพื่อยืนยันว่าอุปกรณ์ปลายทางใดบ้างที่ควบคุมได้ในเครื่อง Intent นี้จะทริกเกอร์ทุกครั้งที่ Google เรียกใช้การสแกนเพื่อค้นหา (ประมาณ 1 ครั้งต่อนาที) ตราบใดที่ตรวจพบว่าฮับออนไลน์อยู่
คุณติดตั้งใช้งานเครื่องจัดการ REACHABLE_DEVICES ในลักษณะเดียวกับเครื่องจัดการ IDENTIFY ยกเว้นว่าเครื่องจัดการของคุณต้องรวบรวมรหัสอุปกรณ์เพิ่มเติมที่เข้าถึงได้โดยอุปกรณ์พร็อกซีในเครื่อง (นั่นคือฮับ) ช่อง device.verificationId มีรหัสอุปกรณ์ในพื้นที่สำหรับอุปกรณ์ปลายทางที่เชื่อมต่อกับฮับ
ReachableDevicesRequest จากแพลตฟอร์ม Local Home มีอินสแตนซ์ของ LocalIdentifiedDevice
คุณจะได้รับรหัสอุปกรณ์พร็อกซีและข้อมูลจากผลการสแกนผ่านอินสแตนซ์นี้
เครื่องจัดการ REACHABLE_DEVICES ควรแสดงผลออบเจ็กต์ ReachableDevicesPayload ที่มีออบเจ็กต์ devices ซึ่งมีอาร์เรย์ของค่า verificationId ที่แสดงถึงอุปกรณ์ปลายทางที่ฮับควบคุม ค่า verificationId ต้องตรงกับ otherDeviceIds ค่าใดค่าหนึ่งจากการตอบกลับ SYNC
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างแฮนเดิล REACHABLE_DEVICES
const reachableDevicesHandler = (request: IntentFlow.ReachableDevicesRequest): IntentFlow.ReachableDevicesResponse => { // Reference to the local proxy device const proxyDeviceId = request.inputs[0].payload.device.id; // Gather additional device ids reachable by local proxy device // ... const reachableDevices = [ // Each verificationId must match one of the otherDeviceIds // in the SYNC response { verificationId: "local-device-id-1" }, { verificationId: "local-device-id-2" }, ]; // Return a response const response: IntentFlow.ReachableDevicesResponse = { intent: Intents.REACHABLE_DEVICES, requestId: request.requestId, payload: { devices: reachableDevices, }, }; return response; };
ใช้แฮนเดิล EXECUTE
เครื่องจัดการ EXECUTE ในแอปจะประมวลผลคำสั่งของผู้ใช้และใช้ Local Home SDK เพื่อเข้าถึงอุปกรณ์อัจฉริยะผ่านโปรโตคอลที่มีอยู่
แพลตฟอร์ม Local Home จะส่งเพย์โหลดอินพุตเดียวกันไปยังฟังก์ชันแฮนเดิล EXECUTE เป็น Intent EXECUTE ไปยังการดำเนินการในระบบคลาวด์ ในทำนองเดียวกัน ตัวแฮนเดิล EXECUTE จะแสดงผลข้อมูลเอาต์พุตในรูปแบบเดียวกับการประมวลผล Intent EXECUTE
คุณสามารถใช้คลาส Execute.Response.Builder ที่ Local Home SDK มีให้เพื่อลดความซับซ้อนในการสร้างการตอบกลับ
แอปของคุณไม่มีสิทธิ์เข้าถึงที่อยู่ IP ของอุปกรณ์โดยตรง แต่ให้ใช้อินเทอร์เฟซ CommandRequest เพื่อสร้างคำสั่งตามโปรโตคอล UDP, TCP หรือ HTTP แทน จากนั้นเรียกใช้ฟังก์ชัน deviceManager.send() เพื่อส่งคำสั่ง
เมื่อกำหนดเป้าหมายคำสั่งไปยังอุปกรณ์ ให้ใช้รหัสอุปกรณ์ (และพารามิเตอร์จากช่อง customData หากมี) จากการตอบกลับ SYNC เพื่อสื่อสารกับอุปกรณ์
ตัวอย่าง
ข้อมูลโค้ดต่อไปนี้แสดงวิธีสร้างแฮนเดิล EXECUTE
const executeHandler = (request: IntentFlow.ExecuteRequest): Promise<IntentFlow.ExecuteResponse> => { // Extract command(s) and device target(s) from request const command = request.inputs[0].payload.commands[0]; const execution = command.execution[0]; const response = new Execute.Response.Builder() .setRequestId(request.requestId); const result = command.devices.map((device) => { // Target id of the device provided in the SYNC response const deviceId = device.id; // Metadata for the device provided in the SYNC response // Use customData to provide additional required execution parameters const customData: any = device.customData; // Convert execution command into payload for local device let devicePayload: string; // ... // Construct a local device command over TCP const deviceCommand = new DataFlow.TcpRequestData(); deviceCommand.requestId = request.requestId; deviceCommand.deviceId = deviceId; deviceCommand.data = devicePayload; deviceCommand.port = customData.port; deviceCommand.operation = Constants.TcpOperation.WRITE; // Send command to the local device return localHomeApp.getDeviceManager() .send(deviceCommand) .then((result) => { response.setSuccessState(result.deviceId, state); }) .catch((err: IntentFlow.HandlerError) => { err.errorCode = err.errorCode || IntentFlow.ErrorCode.INVALID_REQUEST; response.setErrorState(device.id, err.errorCode); }); }); // Respond once all commands complete return Promise.all(result) .then(() => response.build()); };
ใช้ตัวแฮนเดิล QUERY
เครื่องจัดการ QUERY ในแอปจะประมวลผลคำขอของผู้ใช้และใช้ Local Home SDK เพื่อรายงานสถานะของอุปกรณ์อัจฉริยะ
แพลตฟอร์ม Local Home จะส่งเพย์โหลดคำขอเดียวกันไปยังฟังก์ชันแฮนเดิล "QUERY" เช่นเดียวกับ Intent QUERY ไปยังการดำเนินการในระบบคลาวด์ ในทำนองเดียวกัน เครื่องจัดการ QUERY จะแสดงผลข้อมูลในรูปแบบเดียวกับการประมวลผล Intent QUERY
การส่งคำสั่งไปยังอุปกรณ์ที่อยู่หลังฮับ
หากต้องการควบคุมอุปกรณ์ปลายทางที่อยู่หลังฮับ คุณอาจต้องระบุข้อมูลเพิ่มเติมในเพย์โหลดคำสั่งเฉพาะโปรโตคอลที่ส่งไปยังฮับเพื่อให้ฮับระบุได้ว่าคำสั่งนั้นมีไว้สำหรับอุปกรณ์ใด ในบางกรณี ระบบจะอนุมานข้อมูลนี้ได้โดยตรงจากค่า device.id แต่หากไม่ใช่กรณีนี้ คุณควรรวมข้อมูลเพิ่มเติมนี้ไว้เป็นส่วนหนึ่งของฟิลด์ customData
หากคุณสร้างแอปโดยใช้ TypeScript อย่าลืมคอมไพล์แอปเป็น JavaScript คุณสามารถใช้ระบบโมดูลที่ต้องการเพื่อเขียนโค้ดได้ ตรวจสอบว่าเบราว์เซอร์ Chrome รองรับเป้าหมายของคุณ