लोकल फ़ुलफ़िलमेंट ऐप्लिकेशन लागू करना

लोकल फ़ुलफ़िलमेंट की सुविधा देने के लिए, आपको एक ऐप्लिकेशन बनाना होगा. इससे, स्मार्ट होम के इन इंटेंट को मैनेज किया जा सकेगा:

  • IDENTIFY: यह लोकल नेटवर्क से कंट्रोल किए जा सकने वाले स्मार्ट डिवाइसों को ढूंढने में मदद करता है. इंटेंट हैंडलर, उस डेटा को निकालता है जो आपका स्मार्ट डिवाइस, खोज के दौरान दिखाता है. इसके बाद, वह इस डेटा को Google को भेजता है.
  • EXECUTE: यह कमांड चलाने की सुविधा देता है.
  • QUERY: डिवाइस की स्थिति के बारे में क्वेरी करने की सुविधा देता है.
  • REACHABLE_DEVICES: (ज़रूरी नहीं) इससे हब (या ब्रिज) डिवाइस के पीछे मौजूद, स्थानीय तौर पर कंट्रोल किए जा सकने वाले एंड डिवाइसों को खोजने में मदद मिलती है.

यह ऐप्लिकेशन, उपयोगकर्ता के Google Home या Google Nest डिवाइसों पर चलता है. साथ ही, आपके स्मार्ट डिवाइस को Assistant से कनेक्ट करता है. TypeScript (सुझाया गया) या JavaScript का इस्तेमाल करके ऐप्लिकेशन बनाया जा सकता है.

TypeScript का इस्तेमाल करने का सुझाव दिया जाता है, क्योंकि बाइंडिंग का इस्तेमाल करके यह पक्का किया जा सकता है कि आपके ऐप्लिकेशन से मिलने वाला डेटा, प्लैटफ़ॉर्म की उम्मीदों के मुताबिक हो.

एपीआई के बारे में ज़्यादा जानकारी के लिए, Local Home SDK API का रेफ़रंस देखें.

यहां दिए गए स्निपेट में, लोकल फ़ुलफ़िलमेंट ऐप्लिकेशन को शुरू करने और हैंडलर अटैच करने का तरीका बताया गया है.

Standalone
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 बंडल बनाना होगा.

अपने पसंदीदा बंडलर कॉन्फ़िगरेशन के साथ सही प्रोजेक्ट स्ट्रक्चर को बूटस्ट्रैप करने के लिए, लोकल फ़ुलफ़िलमेंट ऐप्लिकेशन प्रोजेक्ट इनिशलाइज़र का इस्तेमाल करें.

प्रोजेक्ट के टेंप्लेट

बंडलर कॉन्फ़िगरेशन चुनने के लिए, npm init कमांड चलाएं. इसके लिए, यहां दिए गए उदाहरण देखें:

कोई नहीं

TypeScript, जिसमें कोई बंडलर कॉन्फ़िगरेशन नहीं है:

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

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 को नई डायरेक्ट्री से बदलें. इसमें लोकल फ़ुलफ़िलमेंट ऐप्लिकेशन प्रोजेक्ट शामिल होगा.

रोलअप

Rollup बंडलर कॉन्फ़िगरेशन के साथ TypeScript:

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 को एक नई डायरेक्ट्री से बदलें, जिसमें लोकल फ़ुलफ़िलमेंट ऐप्लिकेशन प्रोजेक्ट शामिल होगा.

पार्सल

Parcel बंडलर कॉन्फ़िगरेशन के साथ TypeScript:

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 स्क्रिप्ट के साथ काम करता है:

Bundle
cd project-directory/
npm run build

यह स्क्रिप्ट, TypeScript सोर्स को कंपाइल करती है. साथ ही, आपके ऐप्लिकेशन को उसकी डिपेंडेंसी के साथ बंडल करती है. इससे, dist/web सबडायरेक्ट्री में Chrome रनटाइम एनवायरमेंट और dist/node सबडायरेक्ट्री में Node.js रनटाइम एनवायरमेंट के लिए, ऐप्लिकेशन को बंडल किया जाता है.

पुष्टि करें
cd project-directory/
npm run lint
npm run compile
npm test

यह स्क्रिप्ट, आपके TypeScript कोड के सिंटैक्स की पुष्टि करती है. साथ ही, dist/ सबडायरेक्ट्री में कोई आउटपुट जनरेट किए बिना, इसे कंपाइल करती है. इसके अलावा, यह test.ts से अपने-आप होने वाले टेस्ट चलाती है.

विज्ञापन दिखाना
cd project-directory/
npm run start

डेवलपमेंट के दौरान, यह स्क्रिप्ट Chrome और Node.js रनटाइम एनवायरमेंट के लिए, आपके ऐप्लिकेशन बंडल को स्थानीय तौर पर उपलब्ध कराती है.

IDENTIFY हैंडलर को लागू करना

IDENTIFY हैंडलर तब ट्रिगर होगा, जब Google Home या Google Nest डिवाइस रीबूट होगा और उसे ऐसे स्थानीय डिवाइस दिखेंगे जिनकी पुष्टि नहीं हुई है. इनमें हब से कनेक्ट किए गए एंड डिवाइस भी शामिल हैं. Local Home प्लैटफ़ॉर्म, स्कैन कॉन्फ़िगरेशन की जानकारी का इस्तेमाल करके स्थानीय डिवाइसों को स्कैन करेगा. यह जानकारी आपने पहले दी थी. इसके बाद, स्कैन के नतीजों के साथ आपके IDENTIFY हैंडलर को कॉल करेगा.

Local Home प्लैटफ़ॉर्म के IdentifyRequest में, LocalIdentifiedDevice इंस्टेंस का स्कैन डेटा होता है. स्कैन कॉन्फ़िगरेशन के आधार पर, device का सिर्फ़ एक इंस्टेंस पॉप्युलेट होता है. इससे डिवाइस का पता चलता है.

अगर स्कैन के नतीजे आपके डिवाइस से मैच करते हैं, तो आपके IDENTIFY हैंडलर को एक IdentifyResponsePayload ऑब्जेक्ट दिखाना चाहिए. इसमें स्मार्ट होम के मेटाडेटा (जैसे, टाइप, विशेषताएं, और रिपोर्ट की स्थिति) के साथ एक device ऑब्जेक्ट शामिल होता है.

Google, डिवाइस को तब जोड़ता है, जब IDENTIFY रिस्पॉन्स से मिला verificationId, SYNC रिस्पॉन्स से मिली otherDeviceIds वैल्यू में से किसी एक से मैच करता है.

उदाहरण

यहां दिए गए स्निपेट दिखाते हैं कि स्टैंडअलोन डिवाइस और हब इंटिग्रेशन के लिए, IDENTIFY हैंडलर कैसे बनाए जा सकते हैं.

Standalone
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 जवाब में, हब से कनेक्ट किए गए लोकल एंड डिवाइसों के आईडी की जानकारी दी गई है, तो IdentifyResponsePayload में isProxy को true के तौर पर सेट करें.
  • अगर आपके SYNC रिस्पॉन्स में हब डिवाइस की जानकारी नहीं है, तो IdentifyResponsePayload में isLocalOnly को true के तौर पर सेट करें.
  • device.id फ़ील्ड में, हब डिवाइस का लोकल डिवाइस आईडी होता है.

REACHABLE_DEVICES हैंडलर को लागू करना (सिर्फ़ हब इंटिग्रेशन के लिए)

Google, REACHABLE_DEVICES इंटेंट भेजता है, ताकि यह पुष्टि की जा सके कि किन एंड डिवाइसों को स्थानीय तौर पर कंट्रोल किया जा सकता है. यह इंटेंट हर बार तब ट्रिगर होता है, जब Google डिस्कवरी स्कैन चलाता है. यह स्कैन हर मिनट में करीब एक बार चलता है. हालांकि, इसके लिए ज़रूरी है कि हब ऑनलाइन हो.

REACHABLE_DEVICES हैंडलर को IDENTIFY हैंडलर की तरह ही लागू किया जाता है. हालांकि, आपके हैंडलर को उन डिवाइस आईडी के अतिरिक्त आईडी इकट्ठा करने होंगे जिन्हें लोकल प्रॉक्सी (यानी कि हब) डिवाइस से ऐक्सेस किया जा सकता है. device.verificationId फ़ील्ड में, हब से कनेक्ट किए गए एंड डिवाइस का लोकल डिवाइस आईडी होता है.

Local Home प्लैटफ़ॉर्म के ReachableDevicesRequest में, LocalIdentifiedDevice का एक इंस्टेंस शामिल होता है. इस इंस्टेंस से, आपको प्रॉक्सी डिवाइस आईडी के साथ-साथ स्कैन के नतीजों का डेटा भी मिल सकता है.

आपके REACHABLE_DEVICES हैंडलर को एक ReachableDevicesPayload ऑब्जेक्ट दिखाना चाहिए. इसमें एक devices ऑब्जेक्ट शामिल होना चाहिए. इस ऑब्जेक्ट में verificationId वैल्यू का कलेक्शन होना चाहिए. ये वैल्यू, हब से कंट्रोल किए जाने वाले एंड डिवाइसों को दिखाती हैं. verificationId की वैल्यू, SYNC रिस्पॉन्स में मौजूद otherDeviceIds में से किसी एक से मैच होनी चाहिए.

यहां दिए गए स्निपेट में बताया गया है कि REACHABLE_DEVICES हैंडलर कैसे बनाया जा सकता है.

Hub
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 हैंडलर फ़ंक्शन को वही इनपुट पेलोड पास करता है जो आपके क्लाउड फ़ुलफ़िलमेंट के लिए, EXECUTE इंटेंट को पास करता है. इसी तरह, आपका EXECUTE हैंडलर, EXECUTE इंटेंट को प्रोसेस करने के बाद, आउटपुट डेटा को उसी फ़ॉर्मैट में दिखाता है. जवाब बनाने की प्रोसेस को आसान बनाने के लिए, Local Home SDK टूल से मिलने वाली Execute.Response.Builder क्लास का इस्तेमाल किया जा सकता है.

आपके ऐप्लिकेशन के पास डिवाइस के आईपी पते का सीधा ऐक्सेस नहीं है. इसके बजाय, CommandRequest इंटरफ़ेस का इस्तेमाल करके, इनमें से किसी एक प्रोटोकॉल के आधार पर निर्देश बनाएं: यूडीपी, टीसीपी या एचटीटीपी. इसके बाद, निर्देश भेजने के लिए, deviceManager.send() फ़ंक्शन को कॉल करें.

डिवाइसों को निर्देश देते समय, डिवाइस से कम्यूनिकेट करने के लिए, SYNC रिस्पॉन्स से डिवाइस आईडी (और अगर शामिल हो, तो customData फ़ील्ड के पैरामीटर) का इस्तेमाल करें.

उदाहरण

यहां दिए गए कोड स्निपेट से पता चलता है कि 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' हैंडलर फ़ंक्शन को वही अनुरोध पेलोड भेजता है जो आपके क्लाउड फ़ुलफ़िलमेंट के लिए QUERY इंटेंट को भेजा जाता है. इसी तरह, आपका QUERY हैंडलर, QUERY इंटेंट को प्रोसेस करने के बाद, उसी फ़ॉर्मैट में डेटा दिखाता है.

हब से कनेक्ट किए गए डिवाइसों को निर्देश भेजना

हब से जुड़े एंड डिवाइसों को कंट्रोल करने के लिए, आपको हब को भेजे गए प्रोटोकॉल के हिसाब से कमांड पेलोड में अतिरिक्त जानकारी देनी पड़ सकती है. इससे हब को यह पहचानने में मदद मिलती है कि कमांड किस डिवाइस के लिए है. कुछ मामलों में, इसका अनुमान सीधे तौर पर device.id वैल्यू से लगाया जा सकता है. हालांकि, ऐसा न होने पर, आपको इस अतिरिक्त डेटा को customData फ़ील्ड के हिस्से के तौर पर शामिल करना चाहिए.

अगर आपने TypeScript का इस्तेमाल करके अपना ऐप्लिकेशन बनाया है, तो उसे JavaScript में कंपाइल करना न भूलें. अपना कोड लिखने के लिए, अपनी पसंद के मॉड्यूल सिस्टम का इस्तेमाल किया जा सकता है. पक्का करें कि Chrome ब्राउज़र, आपके टारगेट के साथ काम करता हो.