مرحبًا بك في "مركز مطوّري برامج Google Home"، وجهتك الجديدة لتعلّم كيفية تطوير إجراءات منزلية ذكية. ملاحظة: ستواصل إنشاء الإجراءات في وحدة تحكم الإجراءات.

استخدام تطبيق توصيل الطلبات المحلي

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

ولدعم توصيل الطلبات محليًا، يجب إنشاء تطبيق لمعالجة الأغراض المنزلية الذكية التالية:

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

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

ويُوصى باستخدام TypeScript لأنه يمكنك الاستفادة من عمليات الربط للتأكُّد بشكل ثابت من تطابق البيانات التي يعرضها تطبيقك مع الأنواع التي يتوقعها النظام الأساسي.

للحصول على مزيد من التفاصيل عن واجهة برمجة التطبيقات، يمكنك الاطّلاع على مرجع واجهة برمجة التطبيقات لحزمة تطوير البرامج (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 للرمز البرمجي وجميع تبعياته.

استخدِم أداة إعداد المشروع لتطبيق توصيل الطلب المحلي لبدء تشغيل بنية المشروع المناسبة بتهيئة أداة التجميع المفضّلة.

نماذج المشاريع

لاختيار إعدادات أداة تجميع البيانات، شغِّل الأمر 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 ورؤية الأجهزة المحلية التي لم يتم التحقق منها (بما في ذلك الأجهزة النهائية المتصلة بموزع). سيبحث النظام الأساسي Home 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 على جهاز موزع، فإنه سيتعامل مع الموزع كقناة لأجهزة النهاية المتصلة وسيحاول التحقق من أجهزة النهاية هذه.

لتمكين Google من التأكد من وجود جهاز موزع، اتبع هذه التعليمات لمعالج IDENTIFY:

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

تطبيق المعالج REACHABLE_DEVICES (عمليات الدمج المحورية فقط)

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

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

يمرِّر النظام الأساسي Home Home حمولة الإدخال نفسها إلى دالة المعالج EXECUTE نفسها التي تتعلق بالهدف من EXECUTE في تنفيذ السحابة الإلكترونية. وبالمثل، يعرض المعالج EXECUTE بيانات الإخراج بالتنسيق نفسه المستخدَم في معالجة intent في EXECUTE. لتبسيط عملية إنشاء الردود، يمكنك استخدام فئة Execute.Response.Builder التي تقدّمها حزمة تطوير البرامج (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 في التطبيق طلبات المستخدمين ويستخدم حزمة تطوير البرامج (SDK) المحلية للمنزل للإبلاغ عن حالة الأجهزة الذكية.

يمرِّر النظام الأساسي Home Home حمولة الطلب نفسها إلى دالة المعالج 'QUERY' المتعلقة بالقصد من معالجة QUERY لتنفيذ السحابة الإلكترونية. وبالمثل، يعرض المعالج QUERY البيانات بنفس تنسيق معالجة QUERY.

إرسال الأوامر إلى الأجهزة التي تعمل خلف محور

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

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