ใช้แอป Fulfillment ในพื้นที่

คุณต้องสร้างแอปเพื่อรองรับ Intent ของสมาร์ทโฮมเหล่านี้เพื่อรองรับการดําเนินการตามในท้องถิ่น

  • IDENTIFY: รองรับการค้นพบอุปกรณ์อัจฉริยะที่ควบคุมได้ในพื้นที่ เครื่องจัดการ Intent จะแยกข้อมูลที่อุปกรณ์อัจฉริยะแสดงผลระหว่างการสํารวจและส่งข้อมูลนั้นไปยัง Google
  • EXECUTE: รองรับการเรียกใช้คําสั่ง
  • QUERY: รองรับการค้นหาสถานะอุปกรณ์
  • REACHABLE_DEVICES: (ไม่บังคับ) รองรับการสํารวจอุปกรณ์ปลายทางที่ควบคุมได้ในพื้นที่ซึ่งอยู่หลังอุปกรณ์ฮับ (หรือบริดจ์)

แอปนี้ทํางานในอุปกรณ์ Google Home หรือ Google Nest ของผู้ใช้ และเชื่อมต่ออุปกรณ์อัจฉริยะกับ Assistant คุณสามารถสร้างแอปโดยใช้ TypeScript (ที่ต้องการ) หรือ JavaScript

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

สําหรับรายละเอียดเพิ่มเติมเกี่ยวกับ API โปรดดูข้อมูลอ้างอิง API ของ Home 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 สําหรับโค้ดและการอ้างอิงทั้งหมด

ใช้ Project Initializer ของแอปดําเนินการตามคําสั่งซื้อในเครื่องเพื่อเปิดโครงสร้างโปรเจ็กต์ที่เหมาะสมด้วยการกําหนดค่า Bundler ที่คุณต้องการ

เทมเพลตโปรเจ็กต์

ในการเลือกการตั้งค่า Bundle ให้เรียกใช้คําสั่ง 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 ด้วยไดเรกทอรีใหม่ที่จะใส่โปรเจ็กต์แอปดําเนินการในพื้นที่

Webpack

TypeScript ที่มีการกําหนดค่า webpack Bundler:

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 ด้วยไดเรกทอรีใหม่ที่จะใส่โปรเจ็กต์แอปดําเนินการในพื้นที่

ภาพรวม

TypeScript ที่มีการกําหนดค่า Rollup ของ Bundle:

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 ด้วยไดเรกทอรีใหม่ที่จะใส่โปรเจ็กต์แอปดําเนินการในพื้นที่

พัสดุ

TypeScript ที่มีการกําหนดค่า Bundle 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 รีบูตและเห็นอุปกรณ์ในเครือข่ายที่ไม่ได้รับการยืนยัน (รวมถึงอุปกรณ์ปิดท้ายที่เชื่อมต่อกับฮับ) แพลตฟอร์ม Home จะสแกนหาอุปกรณ์ในเครื่องโดยใช้ข้อมูลการกําหนดค่าที่คุณระบุก่อนหน้านี้ และเรียกเครื่องจัดการ IDENTIFY ด้วยผลการสแกน

IdentifyRequest จากแพลตฟอร์ม Home 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 ระบุอุปกรณ์ Hub จะถือว่าอุปกรณ์นั้นๆ เป็นท่อต่ออุปกรณ์ปิดท้ายที่เชื่อมต่อของฮับและพยายามยืนยันอุปกรณ์ปลายทางเหล่านั้น

หากต้องการให้ Google ยืนยันได้ว่ามีอุปกรณ์ Hub อยู่ ให้ทําตามวิธีการต่อไปนี้สําหรับเครื่องจัดการ IDENTIFY ของคุณ

  • หากการตอบกลับ SYNC รายงานรหัสของอุปกรณ์ปลายทางในเครือข่ายที่เชื่อมต่อกับฮับ ให้ตั้งค่า isProxy เป็น true ใน IdentifyResponsePayload
  • หากการตอบกลับ SYNC ไม่รายงานอุปกรณ์ Hub ให้ตั้งค่า isLocalOnly เป็น true ใน IdentifyResponsePayload
  • ช่อง device.id มีรหัสอุปกรณ์ในเครื่องของอุปกรณ์ตัวเครื่องเอง

ใช้เครื่องจัดการ REACHABLE_DEVICES (การผสานรวมฮับเท่านั้น)

Google จะส่ง Intent ของ REACHABLE_DEVICES ไปยังอุปกรณ์ปลายทางที่ควบคุมได้จากเครื่อง จะมีการทริกเกอร์ Intent นี้ทุกครั้งที่ Google เรียกใช้การสแกนการค้นพบ (ทุกๆ 1 นาทีโดยประมาณ) ตราบใดที่ระบบตรวจพบว่าฮับออนไลน์

คุณติดตั้งเครื่องจัดการ REACHABLE_DEVICES ที่คล้ายกับเครื่องจัดการ IDENTIFY เว้นแต่ว่าเครื่องจัดการจะต้องรวบรวมรหัสอุปกรณ์เพิ่มเติมที่เข้าถึงได้โดยพร็อกซีภายในเครื่อง (ซึ่งก็คือฮับ) ช่อง device.verificationId มีรหัสอุปกรณ์ภายในสําหรับผู้ใช้ปลายทางที่เชื่อมต่อกับฮับ

ReachableDevicesRequest จากแพลตฟอร์ม Home 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 เพื่อเข้าถึงอุปกรณ์อัจฉริยะผ่านโปรโตคอลที่มีอยู่

แพลตฟอร์มในเครื่องของบ้านจะส่งเพย์โหลดอินพุตไปยังฟังก์ชันของ EXECUTE แบบเดียวกับ Intent ของ EXECUTE ที่จะทําให้ Cloud Fulfillment เสร็จสมบูรณ์ ในทํานองเดียวกัน เครื่องจัดการ 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 เพื่อรายงานสถานะอุปกรณ์อัจฉริยะ

แพลตฟอร์ม Home ส่งผ่านเปย์โหลดคําขอไปยังฟังก์ชัน "QUERY" ของคําขอเดียวกับ Intent ของ QUERY ที่ดําเนินการตามคําขอระบบคลาวด์ ในทํานองเดียวกัน เครื่องจัดการของ QUERY จะ แสดงข้อมูลในรูปแบบเดียวกับที่ประมวลผล Intent ของ QUERY

การส่งคําสั่งไปยังอุปกรณ์ที่อยู่ด้านหลังฮับ

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

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