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