تنفيذ تطبيق توصيل الطلبات المحلي

ولدعم تلبية الطلبات على المستوى المحلي، عليك إنشاء تطبيق للتعامل مع هذه العوامل. أهداف المنزل المزوّد بأجهزة ذكية:

  • IDENTIFY: يتيح استكشاف الأجهزة الذكية التي يمكن التحكّم فيها محليًا. تشير رسالة الأشكال البيانية يستخرج معالج intent البيانات التي يعرضها جهازك الذكي أثناء الاكتشاف وترسلها في رد إلى Google.
  • EXECUTE: يتيح تنفيذ الأوامر.
  • QUERY: يتيح الاستعلام عن حالة الجهاز.
  • REACHABLE_DEVICES: (اختياري) يتيح استكشاف التطبيقات التي يمكن التحكّم فيها محليًا الأجهزة الطرفية خلف جهاز موزع (أو جسر).

يعمل هذا التطبيق على أجهزة Google Home أو Google Nest الخاصة بالمستخدم ويربط جهازك الذكي بـ مساعد Google ويمكنك إنشاء التطبيق باستخدام TypeScript (مفضّل) أو JavaScript.

ننصحك باستخدام أداة TypeScript لأنه يمكنك الاستفادة من عمليات الربط لضمان تطابق البيانات التي يعرضها تطبيقك مع الأنواع التي تتوقعه المنصة.

لمزيد من التفاصيل حول واجهة برمجة التطبيقات، يمكنك الاطّلاع على مرجع واجهة برمجة التطبيقات لحزمة تطوير البرامج (SDK) لمنزل Local Home

توضِّح المقتطفات التالية كيفية إعداد تطبيق توصيل الطلبات على الجهاز نرفق المعالجات.

مستقل
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 بدليل جديد يحتوي على تطبيق التنفيذ المحلي.

حزمة ويب

TypeScript مع أداة تجميع webpack التكوين:

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 إعدادات أداة التجميع:

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 مع 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 ويجمع تطبيقك مع ملحقاته لبيئة وقت تشغيل 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

أثناء التطوير، يعرض هذا النص البرمجي حِزم تطبيقك لبيئات وقت تشغيل Chrome وNode.js على الجهاز.

تنفيذ معالج IDENTIFY

سيتم تشغيل معالِج IDENTIFY عند إعادة تشغيل جهاز Google Home أو Google Nest و رؤية أجهزة محلية لم يتم التحقق منها (بما في ذلك الأجهزة النهائية المتصلة بمركز التحكم). تشير رسالة الأشكال البيانية ستبحث منصة الشاشة الرئيسية المحلية عن الأجهزة المحلية باستخدام معلومات إعدادات البحث. التي حددتها سابقًا وتطلب من معالج IDENTIFY تقديم نتائج الفحص.

تشير رسالة الأشكال البيانية IdentifyRequest من منصة الصفحة الرئيسية المحلية على بيانات الفحص 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;
  };

تحديد الأجهزة وراء الموزع (hub)

إذا تعرّفت Google على جهاز موزع، سيتعامل مع الموزع على أنه القناة بالأجهزة النهائية المتصلة بالموزع (hub) ومحاولة التحقق من هذه الأجهزة النهائية.

لتمكين Google من التأكُّد من توفُّر جهاز موزع، اتّبِع الخطوات التالية تعليمات لمعالِج IDENTIFY:

  • إذا أشار ردّ SYNC إلى أرقام تعريف الأجهزة النهائية المتصلة بـ الموزع، تم ضبط isProxy على trueفي IdentifyResponsePayload
  • إذا لم تبلغ استجابة SYNC عن جهاز الموزع، اضبط isLocalOnly في شكل true في IdentifyResponsePayload
  • يحتوي الحقل device.id على رقم تعريف الجهاز المحلي لجهاز الموزع نفسه.

تنفيذ المعالِج REACHABLE_جرب (عمليات دمج المركز فقط)

ترسل Google الغرض REACHABLE_DEVICES من أجل تأكيد الأجهزة النهائية. يمكن التحكم فيه محليًا. يتم تفعيل هذا الغرض في كل مرة تُجري فيها Google فحص استكشافي (مرة واحدة كل دقيقة تقريبًا)، طالما تم اكتشاف أن الموزع (hub) أن تكون متصلاً بالإنترنت.

لقد نفّذت معالج REACHABLE_DEVICES بشكل مشابه لمعالج IDENTIFY. المعالِج، باستثناء أنّ المعالج يحتاج إلى جمع أرقام تعريف إضافية للأجهزة يمكن الوصول إليها بواسطة جهاز الخادم الوكيل المحلي (أي الموزع). تشير رسالة الأشكال البيانية يحتوي الحقل device.verificationId على رقم تعريف الجهاز المحلي لجهاز نهائي. المتصلة بالموزع (hub)

تشير رسالة الأشكال البيانية ReachableDevicesRequest من منصة الصفحة الرئيسية المحلية يحتوي على مثيل LocalIdentifiedDevice من خلال هذا المثيل، يمكنك الحصول على معرّف الجهاز الوكيل بالإضافة إلى بيانات من نتائج الفحص.

يجب أن يعرض معالج REACHABLE_DEVICES ReachableDevicesPayload كائن يتضمن كائن devices يحتوي على صفيف verificationId تمثل القيم الأجهزة النهائية التي يتحكم فيها الموزع (hub). تشير رسالة الأشكال البيانية يجب أن تتطابق قيم 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 في التطبيق أوامر المستخدم ويستخدم حزمة تطوير البرامج (SDK) للمنزل المحلي للوصول إلى الأجهزة الذكية من خلال بروتوكول حالي

تمرِّر منصة الصفحة الرئيسية المحلية حمولة البيانات نفسها إلى معالج EXECUTE بالنسبة إلى EXECUTE رغبتهم في تنفيذ الخدمات السحابية. وبالمثل، يعرض معالج EXECUTE. البيانات الناتجة بالتنسيق نفسه المستخدَم في معالجة هدف EXECUTE. لتبسيط إنشاء الرد، يمكنك استخدام Execute.Response.Builder الفئة التي توفّرها حزمة تطوير البرامج للمنزل المحلي.

لا يمكن لتطبيقك الوصول مباشرةً إلى عنوان 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 في التطبيق طلبات المستخدمين ويستخدم حزمة تطوير البرامج (SDK) للمنزل المحلي للإبلاغ عن حالة أجهزتك الذكية.

تمرر منصة الصفحة الرئيسية المحلية حمولة الطلب نفسها إلى "QUERY" المعالج التي تعمل بالنسبة إلى QUERY رغبتهم في تنفيذ الخدمات السحابية. وبالمثل، يعرض معالج QUERY البيانات. بالتنسيق نفسه الناتج عن معالجة هدف QUERY.

إرسال الأوامر إلى الأجهزة الموجودة خلف الموزع (hub)

للتحكّم في الأجهزة النهائية الموجودة خلف وحدة الموزع (hub)، قد تحتاج إلى تقديم معلومات إضافية في حمولة الأوامر الخاصة بالبروتوكول والتي يتم إرسالها إلى الموزع (hub) لتحديد الجهاز الذي يعمل عليه الأمر. في بعض الحالات، قد يكون هذا يمكن الاستنتاج منها مباشرةً من قيمة device.id، ولكن إذا لم يكن الأمر كذلك، يجب تضمين هذه البيانات الإضافية كجزء من الحقل customData.

إذا كنت قد أنشأت تطبيقك باستخدام TypeScript، فتذكر تجميع التطبيق من أجل JavaScript. يمكنك استخدام نظام الوحدات الذي تختاره لكتابة التعليمة البرمجية. تأكَّد من أنّ متصفّح Chrome يتوافق مع هدفك.