لإتاحة التنفيذ المحلي، عليك إنشاء تطبيق لمعالجة طلبات المنزل المزوّد بأجهزة ذكية التالية:
-
IDENTIFY: تتيح هذه الميزة اكتشاف الأجهزة الذكية التي يمكن التحكّم فيها محليًا. يستخرج معالج الطلب البيانات التي يعرضها جهازك الذكي أثناء عملية الاكتشاف ويرسلها في ردّ إلى Google. -
EXECUTE: يتيح تنفيذ الطلبات. -
QUERY: يتيح الاستعلام عن حالة الجهاز. -
REACHABLE_DEVICES: (اختيارية) تتيح هذه السمة اكتشاف الأجهزة الطرفية التي يمكن التحكّم فيها محليًا والمتصلة بجهاز مركز تحكّم (أو جهاز جسر).
يعمل هذا التطبيق على أجهزة Google Home أو أجهزة Google Nest الخاصة بالمستخدم ويربط جهازك الذكي بـ "مساعد Google". يمكنك إنشاء التطبيق باستخدام TypeScript (الخيار المفضّل) أو JavaScript.
ننصح باستخدام TypeScript لأنّه يمكنك الاستفادة من عمليات الربط لضمان أنّ البيانات التي يعرضها تطبيقك تتطابق بشكل ثابت مع الأنواع التي تتوقّعها المنصة.
لمزيد من التفاصيل حول واجهة برمجة التطبيقات، يُرجى الاطّلاع على مرجع واجهة برمجة التطبيقات 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 للرمز البرمجي وجميع العناصر التابعة له.
استخدِم أداة إعداد المشروع لتطبيق التنفيذ المحلي لإنشاء بنية المشروع المناسبة باستخدام إعدادات الحزمة المفضّلة لديك.
نماذج المشاريع
لاختيار إعدادات الحزمة، شغِّل الأمر 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 ويكتشف أجهزة محلية غير متحقق منها (بما في ذلك الأجهزة الطرفية المتصلة بموزّع). ستبحث منصة 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 الغرض REACHABLE_DEVICES لتأكيد الأجهزة الطرفية التي يمكن التحكّم فيها محليًا. يتم تفعيل هذا الغرض في كل مرة تُجري فيها Google فحصًا للاكتشاف (مرة واحدة تقريبًا كل دقيقة)، طالما تم رصد أنّ المحور متصل بالإنترنت.
يمكنك تنفيذ معالج 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 في التطبيق أوامر المستخدم ويستخدم حزمة تطوير البرامج (SDK) الخاصة بـ Local Home للوصول إلى أجهزتك الذكية من خلال بروتوكول حالي.
تمرّر منصة Local Home حمولة الإدخال نفسها إلى دالة معالِج EXECUTE كما هو الحال بالنسبة إلى نية EXECUTE إلى عملية التنفيذ في السحابة الإلكترونية. وبالمثل، يعرض معالج EXECUTE بيانات الإخراج بالتنسيق نفسه الذي يتم من خلاله معالجة نية EXECUTE.
لتبسيط عملية إنشاء الردود، يمكنك استخدام الفئة
Execute.Response.Builder
التي توفّرها حزمة تطوير البرامج (SDK) لمنصة Local Home.
لا يمكن لتطبيقك الوصول مباشرةً إلى عنوان 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 الخاصة بـ Local Home للإبلاغ عن حالة أجهزتك الذكية.
تمرّر منصة Local Home حمولة الطلب نفسها إلى دالة معالِج "QUERY" كما هو الحال بالنسبة إلى نية QUERY إلى عملية التنفيذ في السحابة الإلكترونية. وبالمثل، يعرض معالج QUERY البيانات
بالتنسيق نفسه الذي يتم من خلاله معالجة نية QUERY.
إرسال الأوامر إلى الأجهزة المتصلة بموزّع
للتحكّم في الأجهزة الطرفية المتصلة بوحدة تحكّم، قد تحتاج إلى تقديم معلومات إضافية
في حمولة الأمر الخاص بالبروتوكول التي يتم إرسالها إلى وحدة التحكّم لكي تتمكّن وحدة التحكّم
من تحديد الجهاز الذي يستهدفه الأمر. في بعض الحالات، يمكن استنتاج ذلك مباشرةً من قيمة device.id، ولكن في حال تعذّر ذلك، يجب تضمين هذه البيانات الإضافية كجزء من حقل customData.
إذا أنشأت تطبيقك باستخدام TypeScript، تذكَّر تجميع تطبيقك إلى JavaScript. يمكنك استخدام نظام الوحدات الذي تختاره لكتابة الرمز البرمجي. تأكَّد من أنّ الهدف متوافق مع متصفّح Chrome.