1. قبل البدء
تستخدم الإجراءات المنزلية الذكية أنواع الأجهزة لتمكين "مساعد Google" من معرفة القواعد النحوية التي يجب استخدامها على الجهاز. تحدِّد سمات الجهاز إمكانات نوع جهاز معيّن. يرث الجهاز حالات كل سمة جهاز تتم إضافتها إلى أحد الإجراءات.
يمكنك ربط أي سمات متوافقة بنوع الجهاز الذي اخترته لتخصيص وظائف المستخدمين الأجهزة. إذا أردت تطبيق سمات مخصّصة في "الإجراءات" غير المتوفّرة حاليًا في مخطط الجهاز، ستتيح السمتان الأوضاع والتبديل إعدادات معيّنة" التحكم باستخدام اسم مخصص تحدده.
بالإضافة إلى إمكانات التحكّم الأساسية التي توفّرها الأنواع والسمات، تتضمّن واجهة برمجة تطبيقات Smart Home ميزات إضافية لتحسين تجربة المستخدم. توفّر الردود على الأخطاء ملاحظات تفصيلية من المستخدمين عندما لا تنجح الأهداف. توسّع عملية إثبات هوية المستخدم الثانوي هذه الاستجابات وتضيف أمانًا إضافيًا إلى سمة الجهاز التي تختارها. من خلال إرسال ردود محدّدة عن أخطاء إلى مجموعات الاختبارات الصادرة من "مساعد Google"، يمكن أن يتطلّب "الإجراء المنزلي الذكي" إذنًا إضافيًا لإكمال طلب.
المتطلبات الأساسية
- دليل المطوِّر حول إنشاء المهام المنزلية الذكية
- درس تطبيقي حول الترميز في غسّالة المنزل الذكي
- دليل المطوِّر حول أنواع الأجهزة وسماتها
ما الذي ستقوم ببنائه
في هذا الدرس التطبيقي حول الترميز، ستنشر تكاملاً مسبقًا للمنزل المزوّد بأجهزة ذكية مع Firebase، ثم تتعرَّف على كيفية إضافة سمات غير عادية إلى غسالة المنزل المزوّد بأجهزة ذكية لقياس حجم الحمل ووضع "توربو". وعليك أيضًا تنفيذ تقارير الأخطاء والاستثناءات، وتعلُّم كيفية فرض إقرار شفهي لتشغيل الغسّالة باستخدام الطريقة الثانوية للتحقّق من المستخدم.
ما ستتعرَّف عليه
- كيفية إضافة سمات "الأوضاع" و"التبديلات" إلى الإجراء
- كيفية الإبلاغ عن الأخطاء والاستثناءات
- كيفية تطبيق عملية التحقّق الثانوية من المستخدمين
المتطلبات
- متصفِّح ويب، مثل Google Chrome
- جهاز iOS أو Android وتم تثبيت تطبيق Google Home عليه
- الإصدار 10.16 من Node.js أو إصدار أحدث
- حساب Google
- حساب فوترة على Google Cloud
2. الخطوات الأولى
تفعيل عناصر التحكم في النشاط
لاستخدام "مساعد Google"، يجب مشاركة بيانات أنشطة معيّنة مع Google. يحتاج مساعد Google إلى هذه البيانات ليعمل بشكل سليم؛ مع ذلك، لا تقتصر متطلبات مشاركة البيانات على حزمة تطوير البرامج (SDK). لمشاركة هذه البيانات، أنشئ حساب Google إذا لم يكن لديك حساب. يمكنك استخدام أي حساب على Google، وليس بالضرورة أن يكون هذا الحساب هو حساب المطوِّر الخاص بك.
افتح صفحة عناصر التحكم في النشاط لحساب Google الذي تريد استخدامه مع "مساعد Google".
تأكَّد من أنّ مفاتيح التبديل التالية مفعَّلة:
- الويب النشاط على التطبيقات - عليك أيضًا وضع علامة في مربّع الاختيار تضمين سجلّ Chrome والأنشطة التي تتم على المواقع والتطبيقات والأجهزة التي تستخدم خدمات Google.
- معلومات الجهاز
- الصوت النشاط الصوتي
إنشاء مشروع على "المهام مع مساعد Google"
- انتقِل إلى "المهام مع مساعد Google".
- انقر على مشروع جديد، وأدخِل اسمًا للمشروع، ثم انقر على إنشاء مشروع.
اختيار تطبيق Smart Home
في شاشة "نظرة عامة" ضمن "وحدة التحكّم في الإجراءات"، اختَر الصفحة الرئيسية الذكية.
اختَر بطاقة تجربة المنزل المزوّد بأجهزة ذكية، وانقر على بدء البناء، وسيتم توجيهك بعد ذلك إلى وحدة التحكّم في المشروع.
تثبيت واجهة سطر الأوامر في Firebase
ستتيح لك واجهة سطر أوامر Firebase عرض تطبيقات الويب محليًا ونشر تطبيق الويب في استضافة Firebase.
لتثبيت واجهة سطر الأوامر، شغِّل أمر npm التالي من الوحدة الطرفية:
npm install -g firebase-tools
للتحقّق من تثبيت واجهة سطر الأوامر بشكل صحيح، شغِّل:
firebase --version
يمكنك تفويض واجهة سطر الأوامر في Firebase باستخدام حسابك على Google من خلال تنفيذ ما يلي:
firebase login
تفعيل HomeGraph API
تتيح HomeGraph API إمكانية تخزين الأجهزة وحالاتها وإجراء طلبات بحث عنها ضمن "الرسم البياني المنزلي" الخاص بالمستخدم. لاستخدام واجهة برمجة التطبيقات هذه، يجب أولاً فتح وحدة التحكّم في Google Cloud وتفعيل HomeGraph API.
في وحدة تحكُّم Google Cloud، احرص على اختيار المشروع الذي يتطابق مع "الإجراءات" <project-id>.
، ثم انقر على تفعيل في شاشة مكتبة واجهة برمجة التطبيقات الخاصة بواجهة برمجة التطبيقات HomeGraph.
3- تشغيل تطبيق إجراء التفعيل
الآن بعد إعداد بيئة التطوير، يمكنك نشر مشروع البداية للتأكّد من ضبط كل شيء بشكل صحيح.
الحصول على رمز المصدر
انقر على الرابط التالي لتنزيل نموذج لهذا الدرس التطبيقي حول الترميز على جهاز التطوير:
...أو يمكنك استنساخ مستودع GitHub من سطر الأوامر:
git clone https://github.com/google-home/smarthome-traits.git
فك ضغط ملف ZIP الذي تم تنزيله.
لمحة عن المشروع
يحتوي مشروع المبتدئين على الأدلة الفرعية التالية:
public:
واجهة مستخدم أمامية للتحكم في حالة الغسّالة الذكية ومراقبتها بسهولةfunctions:
خدمة سحابة إلكترونية منفَّذة بالكامل لإدارة الغسّالة الذكية من خلال دوال Cloud في Firebase و"قاعدة بيانات Firebase في الوقت الفعلي"
يتضمن التنفيذ المقدَّم من السحابة الإلكترونية الوظائف التالية في index.js
:
fakeauth
: نقطة نهاية التفويض لربط الحساباتfaketoken
: نقطة نهاية الرمز المميّز لربط الحسابsmarthome
: نقطة نهاية تلبية الطلب للمنزل المزوّد بأجهزة ذكيةreportstate
: يستدعي Home Graph API عند تغيير حالة الجهاز.requestsync
: لتفعيل تحديثات جهاز المستخدم بدون الحاجة إلى إعادة ربط الحساب
الربط بمنصة Firebase
انتقِل إلى دليل washer-start
، ثم أعِدّ واجهة سطر الأوامر في Firebase باستخدام مشروع الإجراءات:
cd washer-start firebase use <project-id>
إعداد مشروع Firebase
إعداد مشروع Firebase.
firebase init
اختَر ميزات واجهة سطر الأوامر وقاعدة البيانات في الوقت الفعلي والوظائف وميزة الاستضافة التي تتضمن "استضافة Firebase".
? Which Firebase CLI features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. ❯◉ Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance ◯ Firestore: Configure security rules and indexes files for Firestore ◉ Functions: Configure a Cloud Functions directory and its files ◉ Hosting: Configure files for Firebase Hosting and (optionally) set up GitHub Action deploys ◯ Hosting: Set up GitHub Action deploys ◯ Storage: Configure a security rules file for Cloud Storage ◯ Emulators: Set up local emulators for Firebase products ◯ Remote Config: Configure a template file for Remote Config ◯ Extensions: Set up an empty Extensions manifest
سيؤدي ذلك إلى تهيئة واجهات برمجة التطبيقات والميزات اللازمة لمشروعك.
قم بتهيئة قاعدة بيانات الوقت الفعلي عندما يُطلب منك ذلك. يمكنك استخدام الموقع التلقائي لمثيل قاعدة البيانات.
? It seems like you haven't initialized Realtime Database in your project yet. Do you want to set it up? Yes ? Please choose the location for your default Realtime Database instance: us-central1
بما أنّك تستخدم رمز مشروع التفعيل، اختَر الملف التلقائي لقواعد الأمان، وتأكَّد من عدم استبدال ملف قواعد قاعدة البيانات الحالي.
? File database.rules.json already exists. Do you want to overwrite it with the Realtime Database Security Rules for <project-ID>-default-rtdb from the Firebase Console? No
إذا كنت تعيد إعداد مشروعك، اختَر استبدال عندما يتم سؤالك عمّا إذا كنت تريد إعداد قاعدة رموز أو استبدالها.
? Would you like to initialize a new codebase, or overwrite an existing one? Overwrite
عند إعداد الدوال، عليك استخدام الملفات التلقائية والتأكد من عدم استبدال ملفات index.js وpackage.json الحالية في نموذج المشروع.
? What language would you like to use to write Cloud Functions? JavaScript ? Do you want to use ESLint to catch probable bugs and enforce style? No ? File functions/package.json already exists. Overwrite? No ? File functions/index.js already exists. Overwrite? No
إذا كنت تعيد إعداد مشروعك، اختَر لا عندما يتم سؤالك عمّا إذا كنت تريد إعداد الدالة/.gitignore أو استبدالها.
? File functions/.gitignore already exists. Overwrite? No
? Do you want to install dependencies with npm now? Yes
أخيرًا، اضبط إعدادات الاستضافة لاستخدام دليل public
في رمز المشروع، واستخدِم ملف index.html الحالي. اختَر لا عندما يُطلب منك استخدام لغة ESLint.
? What do you want to use as your public directory? public ? Configure as a single-page app (rewrite all urls to /index.html)? Yes ? Set up automatic builds and deploys with GitHub? No ? File public/index.html already exists. Overwrite? No
إذا تم تفعيل ESLint عن طريق الخطأ، هناك طريقتان متاحتان لتعطيله:
- باستخدام واجهة المستخدم الرسومية، انتقل إلى مجلد
../functions
ضمن المشروع، ثم اختَر الملف المخفي.eslintrc.js
واحذفه. ولا تخطئ في تصنيفه بالاسم المشابه.eslintrc.json
. - باستخدام سطر الأوامر:
cd functions rm .eslintrc.js
النشر إلى Firebase
الآن بعد أن قمت بتثبيت التبعيات وتهيئة مشروعك، فأنت جاهز لتشغيل التطبيق لأول مرة.
firebase deploy
هذا هو ناتج وحدة التحكّم الذي يُفترض أن يظهر لك:
... ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/<project-id>/overview Hosting URL: https://<project-id>.web.app
يؤدي هذا الأمر إلى نشر تطبيق ويب إلى جانب العديد من وظائف السحابة الإلكترونية لبرنامج Firebase.
افتح عنوان URL للاستضافة في متصفِّحك (https://<project-id>.web.app
) لعرض تطبيق الويب. ستظهر لك الواجهة التالية:
واجهة مستخدم الويب هذه تمثّل نظامًا أساسيًا تابعًا لجهة خارجية من أجل عرض حالات الأجهزة أو تعديلها. لبدء تعبئة قاعدة البيانات بمعلومات الجهاز، انقر على تعديل. لن تظهر لك أي تغييرات في الصفحة، ولكن سيتم تخزين الحالة الحالية للغسّالة في قاعدة البيانات.
حان الآن وقت ربط الخدمة السحابية التي نشرتها بخدمة "مساعد Google" باستخدام وحدة تحكّم المهام.
إعداد مشروع وحدة تحكّم "المهام"
ضمن نظرة عامة > أنشئ الإجراء الخاص بك، ثم اختَر إضافة إجراءات. أدخِل عنوان URL لوظيفة السحابة الإلكترونية التي توفّر تنفيذ عناصر المنزل المزوّد بأجهزة ذكية ثم انقر على حفظ.
https://us-central1-<project-id>.cloudfunctions.net/smarthome
في التطوير > علامة تبويب "الاستدعاء"، أضِف الاسم المعروض للإجراء، وانقر على حفظ. سيظهر هذا الاسم في تطبيق Google Home.
لتفعيل ميزة ربط الحساب، اختَر تطوير > ربط الحساب في شريط التنقل الأيمن. استخدِم إعدادات ربط الحسابات التالية:
معرِّف العميل |
|
سر العميل |
|
عنوان URL للترخيص |
|
عنوان URL للرمز المميز |
|
انقر على حفظ لحفظ إعدادات ربط الحساب، ثم انقر على اختبار لتفعيل الاختبار على مشروعك.
وستتم إعادة توجيهك إلى المحاكي. إذا لم تظهر لك عبارة "الاختبار الآن مفعَّل"، انقر على إعادة ضبط الاختبار للتأكّد من تفعيل الاختبار.
الربط بخدمة "مساعد Google"
لاختبار الإجراء الخاص بمنزلك المزوّد بأجهزة ذكية، يجب ربط مشروعك بحساب Google. يتيح ذلك إجراء الاختبارات من خلال مساحات عرض "مساعد Google" وتطبيق Google Home الذي تم تسجيل الدخول إلى الحساب نفسه عليه.
- افتح إعدادات مساعد Google على هاتفك. تجدر الإشارة إلى أنّه يجب تسجيل الدخول باستخدام الحساب نفسه المستخدَم في وحدة التحكّم.
- انتقِل إلى مساعد Google > الإعدادات > الإدارة الآلية للمنزل (ضِمن "مساعد Google")
- انقر على رمز البحث في أعلى يسار الصفحة.
- ابحث عن تطبيقك التجريبي باستخدام البادئة [test] للعثور على التطبيق التجريبي المحدّد.
- اختَر هذا العنصر. سيصادق "مساعد Google" بعد ذلك مع خدمتك ويرسل طلب
SYNC
، وسيطلب من الخدمة تقديم قائمة بالأجهزة للمستخدم.
يُرجى فتح تطبيق Google Home والتأكّد من إمكانية رؤية جهاز الغسّالة.
مُمْكِنِ التَّحَكُّمْ فِي الْغَسَّالَة بِاسْتِخْدَامْ طَلَبَاتْ صَوْتِيَّة فِي تَطْبِيقْ Google Home. من المفترَض أن تظهر لك أيضًا حالة تغيير في حالة الجهاز في واجهة مستخدم الويب الأمامية الخاصة بالتطبيق على السحابة الإلكترونية.
الآن بعد تفعيل غسّالة أساسية، يمكنك تخصيص الأوضاع المتاحة على جهازك.
4. إضافة وسائل النقل
تتيح السمة action.devices.traits.Modes
للجهاز الحصول على عدد عشوائي من الإعدادات لوضع معيّن، علمًا بأنّه يمكن ضبط إعداد واحد فقط في كل مرّة. ستضيف وضعًا إلى الغسّالة لتحديد حجم غسيل الملابس: صغير أو متوسط أو كبير.
تعديل استجابة المزامنة
يجب إضافة معلومات عن السمة الجديدة إلى ردّك على SYNC
في functions/index.js
. وتظهر هذه البيانات في المصفوفة traits
والكائن attributes
كما هو موضّح في مقتطف الرمز التالي.
index.js
app.onSync(body => {
return {
requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
payload: {
agentUserId: USER_ID,
devices: [{
id: 'washer',
type: 'action.devices.types.WASHER',
traits: [
'action.devices.traits.OnOff',
'action.devices.traits.StartStop',
'action.devices.traits.RunCycle',
// Add Modes trait
'action.devices.traits.Modes',
],
name: { ... },
deviceInfo: { ... },
attributes: {
pausable: true,
//Add availableModes
availableModes: [{
name: 'load',
name_values: [{
name_synonym: ['load'],
lang: 'en',
}],
settings: [{
setting_name: 'small',
setting_values: [{
setting_synonym: ['small'],
lang: 'en',
}]
}, {
setting_name: 'medium',
setting_values: [{
setting_synonym: ['medium'],
lang: 'en',
}]
}, {
setting_name: 'large',
setting_values: [{
setting_synonym: ['large'],
lang: 'en',
}]
}],
ordered: true,
}],
},
}],
},
};
});
إضافة أوامر EXECUTE intent جديدة
في هدف EXECUTE
، أضِف الأمر action.devices.commands.SetModes
كما هو موضّح في مقتطف الرمز التالي.
index.js
const updateDevice = async (execution,deviceId) => {
const {params,command} = execution;
let state, ref;
switch (command) {
case 'action.devices.commands.OnOff':
state = {on: params.on};
ref = firebaseRef.child(deviceId).child('OnOff');
break;
case 'action.devices.commands.StartStop':
state = {isRunning: params.start};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.PauseUnpause':
state = {isPaused: params.pause};
ref = firebaseRef.child(deviceId).child('StartStop');
Break;
// Add SetModes command
case 'action.devices.commands.SetModes':
state = {load: params.updateModeSettings.load};
ref = firebaseRef.child(deviceId).child('Modes');
break;
}
تعديل ردّ QUERY
بعد ذلك، يُرجى تعديل استجابة QUERY
للإبلاغ عن الحالة الحالية للغسّالة.
أضِف التغييرات المعدّلة إلى الدالتين queryFirebase
وqueryDevice
للحصول على الحالة كما هي مُخزَّنة في "قاعدة البيانات في الوقت الفعلي".
index.js
const queryFirebase = async (deviceId) => {
const snapshot = await firebaseRef.child(deviceId).once('value');
const snapshotVal = snapshot.val();
return {
on: snapshotVal.OnOff.on,
isPaused: snapshotVal.StartStop.isPaused,
isRunning: snapshotVal.StartStop.isRunning,
// Add Modes snapshot
load: snapshotVal.Modes.load,
};
}
const queryDevice = async (deviceId) => {
const data = await queryFirebase(deviceId);
return {
on: data.on,
isPaused: data.isPaused,
isRunning: data.isRunning,
currentRunCycle: [{ ... }],
currentTotalRemainingTime: 1212,
currentCycleRemainingTime: 301,
// Add currentModeSettings
currentModeSettings: {
load: data.load,
},
};
};
تعديل حالة التقرير
أخيرًا، يمكنك تعديل دالة reportstate
للإبلاغ عن إعدادات التحميل الحالية للغسالة إلى الرسم البياني المنزلي.
index.js
const requestBody = {
requestId: 'ff36a3cc', /* Any unique ID */
agentUserId: USER_ID,
payload: {
devices: {
states: {
/* Report the current state of your washer */
[context.params.deviceId]: {
on: snapshot.OnOff.on,
isPaused: snapshot.StartStop.isPaused,
isRunning: snapshot.StartStop.isRunning,
// Add currentModeSettings
currentModeSettings: {
load: snapshot.Modes.load,
},
},
},
},
},
};
النشر إلى Firebase
شغِّل الأمر التالي لنشر الإجراء المُعدَّل:
firebase deploy --only functions
بعد اكتمال النشر، انتقِل إلى واجهة مستخدم الويب وانقر على زر إعادة التحميل في شريط الأدوات. يؤدي ذلك إلى تفعيل عملية "مزامنة الطلب" حتى يتلقّى "مساعد Google" بيانات الاستجابة المعدّلة بخصوص "SYNC
".
يمكنك الآن توجيه طلب لضبط وضع الغسّالة، مثلاً:
"Ok Google، أريد ضبط حِمل الغسّالة على حجم كبير"
بالإضافة إلى ذلك، يمكنك طرح أسئلة حول غسّالة الملابس، مثلاً:
"Ok Google، ما هي عبء الغسّالة؟"
5- إضافة مفاتيح التبديل
تمثّل السمة action.devices.traits.Toggles
جوانب مذكورة في الجهاز مضبوطة على حالة "صحيح" أو "خطأ"، مثلاً ما إذا كانت الغسالة في وضع "توربو".
تعديل استجابة المزامنة
في ردّ SYNC
، عليك إضافة معلومات حول السمة الجديدة للجهاز. وسيظهر في المصفوفة traits
والكائن attributes
كما هو موضّح في مقتطف الرمز التالي.
index.js
app.onSync(body => {
return {
requestId: 'ff36a3cc-ec34-11e6-b1a0-64510650abcf',
payload: {
agentUserId: USER_ID,
devices: [{
id: 'washer',
type: 'action.devices.types.WASHER',
traits: [
'action.devices.traits.OnOff',
'action.devices.traits.StartStop',
'action.devices.traits.RunCycle',
'action.devices.traits.Modes',
// Add Toggles trait
'action.devices.traits.Toggles',
],
name: { ... },
deviceInfo: { ... },
attributes: {
pausable: true,
availableModes: [{
name: 'load',
name_values: [{
name_synonym: ['load'],
lang: 'en'
}],
settings: [{ ... }],
ordered: true,
}],
//Add availableToggles
availableToggles: [{
name: 'Turbo',
name_values: [{
name_synonym: ['turbo'],
lang: 'en',
}],
}],
},
}],
},
};
});
إضافة أوامر تنفيذ intent جديدة
في هدف EXECUTE
، أضِف الأمر action.devices.commands.SetToggles
كما هو موضّح في مقتطف الرمز التالي.
index.js
const updateDevice = async (execution,deviceId) => {
const {params,command} = execution;
let state, ref;
switch (command) {
case 'action.devices.commands.OnOff':
state = {on: params.on};
ref = firebaseRef.child(deviceId).child('OnOff');
break;
case 'action.devices.commands.StartStop':
state = {isRunning: params.start};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.PauseUnpause':
state = {isPaused: params.pause};
ref = firebaseRef.child(deviceId).child('StartStop');
break;
case 'action.devices.commands.SetModes':
state = {load: params.updateModeSettings.load};
ref = firebaseRef.child(deviceId).child('Modes');
break;
// Add SetToggles command
case 'action.devices.commands.SetToggles':
state = {Turbo: params.updateToggleSettings.Turbo};
ref = firebaseRef.child(deviceId).child('Toggles');
break;
}
تعديل ردّ QUERY
أَخِيرًا، لَازِمْ تَعْدِيلِ اسْتِجَابِةْ QUERY
عَلَشَانْ تِعَرَّفْ عَلَى وَضْعِ التَّشْغِيلِ الْلِّي فِي الْغَسَّالَة. أضِف التغييرات المعدَّلة إلى الدالتين queryFirebase
وqueryDevice
للحصول على حالة التبديل كما هو مخزّن في قاعدة البيانات في الوقت الفعلي.
index.js
const queryFirebase = async (deviceId) => {
const snapshot = await firebaseRef.child(deviceId).once('value');
const snapshotVal = snapshot.val();
return {
on: snapshotVal.OnOff.on,
isPaused: snapshotVal.StartStop.isPaused,
isRunning: snapshotVal.StartStop.isRunning,
load: snapshotVal.Modes.load,
// Add Toggles snapshot
Turbo: snapshotVal.Toggles.Turbo,
};
}
const queryDevice = async (deviceId) => {
const data = queryFirebase(deviceId);
return {
on: data.on,
isPaused: data.isPaused,
isRunning: data.isRunning,
currentRunCycle: [{ ... }],
currentTotalRemainingTime: 1212,
currentCycleRemainingTime: 301,
currentModeSettings: {
load: data.load,
},
// Add currentToggleSettings
currentToggleSettings: {
Turbo: data.Turbo,
},
};
};
تعديل حالة التقرير
أَخِيرًا، عَدِّلْ دالّة reportstate
لِإِبْلَاغْ Home Graph عمّا إذا كانت الغسالة مضبوطة على الوضع توربو.
index.js
const requestBody = {
requestId: 'ff36a3cc', /* Any unique ID */
agentUserId: USER_ID,
payload: {
devices: {
states: {
/* Report the current state of your washer */
[context.params.deviceId]: {
on: snapshot.OnOff.on,
isPaused: snapshot.StartStop.isPaused,
isRunning: snapshot.StartStop.isRunning,
currentModeSettings: {
load: snapshot.Modes.load,
},
// Add currentToggleSettings
currentToggleSettings: {
Turbo: snapshot.Toggles.Turbo,
},
},
},
},
},
};
النشر إلى Firebase
شغِّل الأمر التالي لنشر الدوال المُحدَّثة:
firebase deploy --only functions
انقر على الزر إعادة تحميل في واجهة المستخدم على الويب لتشغيل طلب مزامنة بعد اكتمال النشر.
مُمْكِنْ دِلْوَقْتِي تَوْجِيهْ طَلَبْ ضَبْطِ الْغَسَّالَة عَلَى وَضْعْ تَرْبُوطْ عَنْ طَرِيقْ قَوْلْ:
"Ok Google، أريد تشغيل التوربو للغسّالة"
يمكنك أيضًا التحقّق ممّا إذا كانت الغسالة في وضع التوربو من خلال طرح السؤال التالي:
"Ok Google، هل الغسّالة في وضع التوربو؟"
6- الإبلاغ عن الأخطاء والاستثناءات
عند معالجة الأخطاء في الإجراء الخاص داخل المنزل المزوّد بأجهزة ذكية، يمكنك إبلاغ المستخدمين بحدوث مشاكل تؤدّي إلى عدم استجابة "EXECUTE
" و"QUERY
". توفّر الإشعارات تجربة مستخدم أكثر إيجابية عند تفاعلهم مع الجهاز الذكي والإجراء.
عند تعذّر تنفيذ طلب EXECUTE
أو QUERY
، من المفترض أن يعرض الإجراء الخاص بك رمز خطأ. على سبيل المثال، إذا أردت عرض رسالة خطأ عندما يحاول أحد المستخدمين تشغيل الغسّالة مع فتح غطاء الجهاز، ستظهر استجابة EXECUTE
كمقتطف الرمز التالي:
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"commands": [
{
"ids": [
"456"
],
"status": "ERROR",
"errorCode": "deviceLidOpen"
}
]
}
}
والآن، عندما يطلب أحد المستخدمين تشغيل الغسّالة، يستجيب "مساعد Google" بقول:
"غطاء الغسّالة مفتوح. يُرجى إغلاقه وإعادة المحاولة".
تتشابه الاستثناءات مع الأخطاء، ولكنها تشير إلى ارتباط تنبيه بأمر، ما قد يؤدي إلى حظر التنفيذ الناجح أو عدم حظره. يمكن أن يقدّم استثناء معلومات ذات صلة باستخدام سمة StatusReport
، مثل مستوى البطارية أو تغيير الحالة مؤخرًا. يتم عرض رموز الاستثناء التي لا تحظر الحظر مع حالة SUCCESS
، بينما يتم عرض رموز استثناء الحظر بالحالة EXCEPTIONS
.
يوجد مثال لرد مع استثناء في مقتطف الرمز التالي:
{
"requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
"payload": {
"commands": [{
"ids": ["123"],
"status": "SUCCESS",
"states": {
"online": true,
"isPaused": false,
"isRunning": false,
"exceptionCode": "runCycleFinished"
}
}]
}
}
يستجيب "مساعد Google" بقول:
"انتهى تشغيل الغسّالة"
لإضافة ميزة إعداد تقارير الأخطاء في الغسّالة، افتح functions/index.js
وأضِف تعريف فئة الخطأ كما هو موضّح في مقتطف الرمز التالي:
index.js
app.onQuery(async (body) => {...});
// Add SmartHome error handling
class SmartHomeError extends Error {
constructor(errorCode, message) {
super(message);
this.name = this.constructor.name;
this.errorCode = errorCode;
}
}
تعديل استجابة التنفيذ لعرض رمز الخطأ وحالة الخطأ:
index.js
const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
for (const device of command.devices) {
for (const execution of command.execution) {
executePromises.push( ... )
//Add error response handling
.catch((error) => {
functions.logger.error('EXECUTE', device.id, error);
result.ids.push(device.id);
if(error instanceof SmartHomeError) {
result.status = 'ERROR';
result.errorCode = error.errorCode;
}
})
);
}
}
}
يستطيع "مساعد Google" الآن إخبار المستخدمين بأي رمز خطأ يتم الإبلاغ عنه. سترى مثالاً محددًا في القسم التالي.
7. إضافة عملية إثبات هوية مستخدم ثانوي
يجب تنفيذ عملية التحقّق الثانوي من المستخدم في الإجراء الخاص بك إذا كان جهازك يحتوي على أي أوضاع يجب تأمينها أو يجب أن يقتصر على مجموعة معيّنة من المستخدمين المصرَّح لهم، مثل تحديث البرنامج أو إيقاف ميزة إيقاف التفاعل.
يمكنك تنفيذ التحقُّق الثانوي من المستخدِم على جميع أنواع الأجهزة وسماتها، مع تخصيص ما إذا كان التحقُّق من الأمان سيحدث في كل مرة أو في حال استيفاء معايير محدَّدة.
هناك ثلاثة أنواع معتمَدة من الاختبارات:
No
challenge
: طلب واستجابة لا يستخدمان اختبار مصادقة (هذا هو السلوك التلقائي)ackNeeded
— عملية تحقق ثانوية من المستخدم تتطلب إقرارًا صريحًا (نعم أو لا)pinNeeded
— عملية تحقق ثانوية من المستخدم تتطلب رقم تعريف شخصي (PIN)
في هذا الدرس التطبيقي حول الترميز، أضِف تحدّي ackNeeded
إلى الأمر الخاص بتشغيل الغسّالة والوظيفة لعرض رسالة خطأ في حال تعذّر إكمال عملية التحقّق الثانوية.
افتح functions/index.js
وأضِف تعريفًا لفئة الخطأ يعرض رمز الخطأ ونوع الاختبار كما هو موضّح في مقتطف الرمز التالي:
index.js
class SmartHomeError extends Error { ... }
// Add secondary user verification error handling
class ChallengeNeededError extends SmartHomeError {
/**
* Create a new ChallengeNeededError
* @param {string} suvType secondary user verification challenge type
*/
constructor(suvType) {
super('challengeNeeded', suvType);
this.suvType = suvType;
}
}
عليك أيضًا تعديل استجابة التنفيذ لعرض الخطأ challengeNeeded
على النحو التالي:
index.js
const executePromises = [];
const intent = body.inputs[0];
for (const command of intent.payload.commands) {
for (const device of command.devices) {
for (const execution of command.execution) {
executePromises.push( ... )
.catch((error) => {
functions.logger.error('EXECUTE', device.id, error);
result.ids.push(device.id);
if(error instanceof SmartHomeError) {
result.status = 'ERROR';
result.errorCode = error.errorCode;
//Add error response handling
if(error instanceof ChallengeNeededError) {
result.challengeNeeded = {
type: error.suvType
};
}
}
})
);
}
}
}
وأخيرًا، عدِّل updateDevice
لطلب الإقرار الصريح بتشغيل الغسّالة أو إيقافها.
index.js
const updateDevice = async (execution,deviceId) => {
const {challenge,params,command} = execution; //Add secondary user challenge
let state, ref;
switch (command) {
case 'action.devices.commands.OnOff':
//Add secondary user verification challenge
if (!challenge || !challenge.ack) {
throw new ChallengeNeededError('ackNeeded');
}
state = {on: params.on};
ref = firebaseRef.child(deviceId).child('OnOff');
break;
...
}
return ref.update(state)
.then(() => state);
};
النشر إلى Firebase
شغِّل الأمر التالي لنشر الدالة المُحدَّثة:
firebase deploy --only functions
بعد نشر الرمز المعدّل، يجب الإقرار شفهيًا بالإجراء عندما تطلب من "مساعد Google" تشغيل الغسّالة أو إيقافها، كما يلي:
أنت: "Ok Google، أريد تشغيل الغسّالة"
مساعد Google: "هل تريد فعلاً تشغيل الغسّالة؟"
أنت: "نعم"
يمكنك أيضًا الاطّلاع على رد تفصيلي لكل خطوة من خطوات العملية الثانوية للتحقّق من المستخدم من خلال فتح سجلّات Firebase.
8. تهانينا
تهانينا! لقد وسّعت نطاق ميزات "إجراءات المنزل المزوّد بأجهزة ذكية" من خلال السمتين Modes
وToggles
، وأمنت تنفيذ هذه الإجراءات من خلال التحقق الثانوي من المستخدم.
مزيد من المعلومات
في ما يلي بعض الأفكار التي يمكنك تنفيذها للتعمق أكثر:
- يمكنك إضافة إمكانيات التنفيذ المحلي إلى أجهزتك.
- استخدِم نوعًا مختلفًا من الاختبارات الثانوية للتحقّق من هوية المستخدم لتعديل حالة جهازك.
- عدِّل استجابة QUERY لسمة
RunCycle
ليتم تحديثها ديناميكيًا. - يمكنك الاطّلاع على نموذج GitHub هذا.