لدعم تلبية الطلبات على المستوى المحلي، تحتاج إلى إنشاء تطبيق للتعامل مع الأهداف المنزلية الذكية التالية:
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 مع رصد أجهزة محلية لم يتم التحقق منها (بما في ذلك الأجهزة النهائية المتصلة بوحدة تحكُّم). وستبحث منصة Local Home عن الأجهزة المحلية باستخدام معلومات إعدادات الفحص
التي حدّدتها سابقًا، وستتصل بمعالج IDENTIFY
مع نتائج الفحص.
يحتوي
IdentifyRequest
من منصة Local Home على بيانات الفحص لمثيل
LocalIdentifiedDevice
. تتم تعبئة مثيل device
واحد فقط استنادًا إلى إعدادات الفحص
التي اكتشفت الجهاز.
إذا كانت نتائج الفحص تطابق جهازك، من المفترض أن يعرض معالج IDENTIFY
كائن
IdentifyResponsePayload
يتضمّن عنصر device
مع بيانات وصفية للمنزل المزوّد بأجهزة ذكية (مثل الأنواع والسمات وحالة التقرير).
سينشئ محرّك بحث Google عملية ربط للجهاز في حال تطابق verificationId
في الاستجابة IDENTIFY
مع إحدى قيم otherDeviceIds
التي تعرضها الاستجابة SYNC
.
مثال
توضّح المقتطفات التالية كيفية إنشاء معالِجات IDENTIFY
لعمليات دمج الأجهزة المستقلّة والموزع (Hub) على التوالي.
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 من التأكد من توفّر جهاز الموزع (hub)، يُرجى اتّباع التعليمات التالية الخاصة بمعالج IDENTIFY
:
- إذا كانت استجابة
SYNC
تشير إلى أرقام تعريف الأجهزة النهائية المحلية المتصلة بالمركز، اضبطisProxy
علىtrue
فيIdentifyResponsePayload
. - إذا لم تبلّغ استجابة
SYNC
عن جهاز الإرساء، اضبطisLocalOnly
علىtrue
فيIdentifyResponsePayload
. - يحتوي الحقل
device.id
على رقم تعريف الجهاز المحلي لجهاز الموزع نفسه.
تنفيذ المعالج REACHABLE_أجهزتك (عمليات دمج الموزعات فقط)
تُرسل 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 حمولة الإدخال نفسها إلى دالة معالج 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 متوافق مع هدفك.