مكونات صفحة ويب SVG لإنترنت الأشياء وصانعيها (الجزء 2)

نشرت: 2022-03-10
ملخص سريع ↬ عند تصميم واجهات لصفحة ويب إنترنت الأشياء ، يكون لدى المرء دائمًا العديد من الخيارات. في الجزء السابق من هذه المقالة ، ألقى ريتشارد ليدي الضوء على معنى إنترنت الأشياء وكيف يمكن استخدام Vue.js لاستضافة مجموعات من واجهات إنترنت الأشياء بين الإنسان والآلة. اليوم ، دعونا نلقي نظرة فاحصة على لوحات التحميل البطيء وكيفية الحفاظ على حالة Vue متزامنة مع الأجهزة.

لذلك ، لدينا بالفعل طرق للتحميل الديناميكي لقائمة من أيقونات SVG المصممة للتفاعل عن طريق تحميل اللوحات إذا رغبنا في ذلك ، لكن الرموز لم تكن مكونات فعلية. تمكنا من استخدام خدعة بسيطة تتمثل في إدخال SVG لكل رمز وتمريره إلى تطبيق Vue. كان الأمر بسيطًا بما يكفي لإنشاء قائمة بالأيقونات ، وكان رد فعل كل رمز بطريقة مماثلة باستثناء الاختلافات الصغيرة في البيانات. جعل اختلاف البيانات من الممكن ربط اسم لوحة بكل رمز بطريقة تمكن معالج النقر فوق الزر من تمريرها.

عندما يتم تحميل لوحة في شكل مكون Vue ، يجب تحميل كل شيء عن اللوحة ومكوناتها والقوالب وجافا سكريبت والمزيد. لذا ، فإن مهمة إدارة تحميل اللوحة أكبر مما واجهناه حتى الآن في هذه المناقشة.

لنلقِ نظرة على طريقة Vue لتوفير خطاف للتحميل غير المتزامن. المقتطف التالي من دليل Vue.

 Vue.component('async-example', function (resolve, reject) { setTimeout(function () { // Pass the component definition to the resolve callback resolve({ template: '<div>I am async!</div>' }) }, 1000) })

يخبرنا الدليل أن وظيفة setTimeout هي مثال على كيفية استخدام التزامن مع مكونات Vue. لاحظ أنه في حالة وجود كائن سابقًا كمعامل ثاني لـ Vue.component ، توجد الآن وظيفة يشار إليها باسم وظيفة المصنع. ضمن رد النداء resolve هو تعريف مكون ، كان من الممكن أن يكون المعلمة الثانية لـ Vue.component من قبل.

المزيد بعد القفز! أكمل القراءة أدناه ↓

لذلك ، كان علي أن أحدق في هذا المثال برهة قبل أن يصبح منطقيًا بالنسبة لي. هذا مثال آخر يناسبني أكثر:

 Vue.component('async-example', function (resolve, reject) { // Vue will call this function and promise itself to handle // it when it gets back with data. // this function can then call a promising object loader // here the 'loader' function is some abstract function. // Most likely the application will use 'fetch' // but it could be something else. loader('/my/resource/on/server.json'). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } );

يبدو أن الشيء الصحيح الذي يجب فعله لجعل وظيفة أكثر عمومية للتغلب على هذا النموذج.

 function componentLoader(c_name,resource_url) { Vue.component(c_name, function (resolve, reject) { loader(resource_url). then(function (JSON_data) { var object = transformJSONToJSObject(JSON_data); resolve(object) }).catch( (error) => { handle it } ); }

لذلك ، بشكل عام ، لتحميل أحد المكونات ، نحتاج فقط إلى سطر مثل التالي:

 componentLoader('ThermoPanel','./JSON/thermo-panel.json');

والآن ، ما هو JSON الذي يتم تحميله؟ يمكن أن يشمل كل شيء عن المكون. في هذه الحالة ، كمكون لوحة ، يمكن أن تشمل موازين الحرارة ومفاتيح الماكينة والمنزلقات والمقاييس والمزيد. بينما يبدو أنه من الأفضل الاحتفاظ بأجزاء المكونات على صفحة الويب ، فقد يكون من الأفضل في الواقع استخدام حقل المكون الفرعي الموجود في المثال الأطول لـ "اللوحة الحرارية" التي صنعناها من قبل وكذلك للألواح الأخرى التي تم إنشاؤها بشكل مشابه. سيحتوي JSON على هيكل لوحة كامل.

ومع ذلك ، إذا لاحظ القارئ تضمين استدعاء الوظيفة لـ transformJSONToJSObject ، فسوف يفهم أن JSON قد يتم ترميزها بطريقة ما لتسهيل النقل وتسهيل التعامل مع التعريف على الخادم. بعد كل شيء ، سيتضمن التعريف قوالب SVG كاملة ، وتعريفات للوظائف ، وتعبيرات JavaScript أخرى. أيضًا ، قد يحتوي كائن JSON على أكثر من مجرد تعريف اللوحة لأن بعض المعلومات قد تساعد ببساطة في إمساك الدفاتر أو التحقق من الصحة. لذلك ، يمكن للمرء أن يتوقع أنه سيكون هناك بعض العلاج للكائن عند الاستلام.

بالنسبة للترميز ، يمكن تشفير البيانات الواردة من الخادم بعدة طرق. ربما سيكون مجرد عنوان URL مشفر. أو بشكل أكثر أمانًا ، قد يكون مشفرًا. لهذه المناقشة ، يمكننا فقط استخدام ترميز URL.

لا شك أن بعض الأدوات المتوفرة لإنشاء تطبيقات Vue تهتم بتحويل JSON. لكن هذه المناقشة تجنبت حتى الآن استخدام أدوات سطر الأوامر. هذا الإغفال ليس بهذا السوء لأننا استخدمنا أيضًا Vue مع الحد الأدنى من الموارد ، باستخدام علامة نصية واحدة فقط للإشارة إلى CDN. ومع ذلك ، أنا بالتأكيد أوصي بالنظر في أدوات سطر الأوامر خاصة لتنظيم المشاريع.

عندما يصل JSON إلى الصفحة ، نظرًا لأنه تم تجميع المكون بالكامل مع مكونات فرعية ، فلا داعي لمزيد من العمل لجلب الأجزاء. يمكننا أن نفترض أن جميع المكونات سوف تأتي محددة بالكامل لبقية هذه المناقشة. ولكن ، سيتطلب تجميع التسلسلات الهرمية للمكونات الكاملة أدوات سطر الأوامر في مرحلة ما.

ستتطلب عملية تحرير SVG أيضًا بعض العمل. تسمح عمليات تحرير SVG للمصمم برسم لوحة وجميع المكونات الموجودة عليها. ولكن ، يجب تحديد كل مكون فرعي ، أو استدعاؤه في مجموعة ، أو منحه نائبًا. تتطلب أي طريقة لاستخدام الرسم بعض المعالجة لـ SVG بحيث يمكن لعلامات مكون Vue استبدال المجموعات أو العناصر الرسومية. بهذه الطريقة ، يمكن أن يصبح أي عرض فنان نموذجًا. وسيتعين تفكيك المكونات الفرعية المرسومة في قوالب لمكونات Vue الفرعية.

هذا النوع من البخل مخالف لسير العمل في معظم أطر عمل جافا سكريبت. الأطر تدور حول تجميع الصفحات. ولكن ، التحرير أو الرسم ، ينتج عنه شيء تم تجميعه بالفعل بواسطة فنان. من الناحية العملية ، لا توفر نتيجة التحرير ملفًا نصيًا يتوافق مباشرةً مع تعريف مكون إطار العمل.

قد يتم النظر في المزيد حول عملية التحرير في بعض المناقشات الأخرى. هناك الكثير لذلك. لكن في الوقت الحالي ، لدينا الأدوات التي نحتاجها لتحميل المكونات الهرمية وجعلها تنبض بالحياة.

تطبيق كسول

لبناء لوحة إنترنت الأشياء ، لدينا بالفعل شريط اختيار يستجيب لعمليات البحث. ولدينا طريقة لتحميل المكونات عندما نحتاج إليها. نحن فقط بحاجة لربط هذه الأجزاء. وأخيرًا ، علينا التأكد من ظهور اللوحات وأنها تبدأ في العمل عندما تفعل ذلك.

يوفر التحميل البطيء للوحات الذي يتم إجراؤه بواسطة الكود غير المتزامن أعلاه مخططًا للفكرة. لكن لحسن الحظ ، جرب بعض الأشخاص لإيجاد طرق للتأكد من إمكانية تحميل جميع أنواع المكونات. يوجد إدخال رمز واحد يوضح كيفية تحديث تطبيقات Vue بمكونات جديدة من أنواع مختلفة. هذه هي الآلية المطلوبة لتحديث جزء معين من الصفحة بأنواع مختلفة من اللوحات.

مع القدرة على إضافة أنواع مختلفة من اللوحات وبآلية بسيطة لتحميل تعريفاتها ، يمكننا أخيرًا الحصول على صفحة البحث الخاصة بنا.

إليك HTML الذي نحتاجه في صفحتنا حتى يتمكن تطبيق Vue من وضع المكونات ديناميكيًا:

 <template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name"></component> </template>

علامة component هي علامة وصفية Vue. انظر المرجع للمكونات الديناميكية. الخصائص والسمات الخاصة المستخدمة لعلامة component في هذه الحالة هي مفتاح. is سمة للمكونات الديناميكية. ويضمن key أن يكون للأطفال الجدد هويات مختلفة عن بعضهم البعض ويساعد Vue في تحديد ما يرسمه.

يجب أن يكون لدى أطفال نفس الوالد المشترك مفاتيح فريدة. ستؤدي المفاتيح المكررة إلى حدوث أخطاء في العرض ".

ستتكرر علامة template خلال المكونات التي يتم توفيرها في حقل بيانات panelList الخاص بالتطبيق.

لذلك ، بدءًا من تعريف Vue على مستوى التطبيق لتطبيق الرمز ، يمكننا إجراء تغييرات لتضمين قائمة اللوحة في عناصر البيانات. (دعنا نسميها الآن panelApp).

 var panelApp = new Vue({ el: '#PanelApp', data: { iconList: [ // Where is the data? Still on the server. ], panelList: [ ], queryToken : "Thermo Batches" // picked a name for demo }, methods : { goGetPanel: function (pname) { // var url = panelURL(pname); // this is custom to the site. fetch(url).then((response) => { // this is now browser native response.text().then((text) => { var newData = decodeURIComponent(text); eval(pHat); // widgdef = object def, must be assignment pHat = widgdef; var pnameHat = pname + pcount++; pHat.name = pnameHat; // this is needed for the key this.panelList.push(pHat); // now it's there. }).catch( error => { /* handle it */ }); } } });

إلى جانب الإضافة في اللوحة ، goGetPanel الآن في نموذج مطلوب للحصول على تعريف مكون من قاعدة بيانات أو متجر آخر. يجب أن يكون جانب الخادم حريصًا بشأن تقديم كود JavaScript بالتنسيق الصحيح. بالنسبة لما يبدو عليه الكائن قادمًا من الخادم ، فقد رأينا ذلك بالفعل. إنه نوع الكائن المستخدم كمعامل لـ Vue.component .

إليك الجسم الكامل لتطبيق Vue الذي يوفر قائمة كنتيجة بحث ومكانًا لوضع اللوحات التي تم جلبها من الخادم عندما ينقر المستخدم على أيقونة.

 <div> <!-- Recognize the name from the Vue doc --> <div> <h2 itemprop="name">Request MCU Groups</h2> <p itemprop="description">These are groups satistfying this query: {{queryToken}}.</p> <button>Find All</button> <button>Find 5 Point</button> <button>Find 6 Point</button> </div> <!-- Here is a Vue loop for generating a lit --> <div class="entryart"> <button v-for="iconEntry in iconList" @click="goGetPanel(iconEntry.name)" > <div v-html="iconEntry.icon"> </div> </button> </div> <div class="entryart" > <template v-for="(panel, index) in panelList"> <component :is="panel" :key="panel.name" :ref="panel.name" ></component> </template> </div> </div>

في قسم div الأخير ، أصبح لعلامة component الآن معلمة ref مرتبطة باسم اللوحة. تسمح المعلمة ref لتطبيق Vue بتحديد المكون الذي سيتم تحديثه بالبيانات والحفاظ على المكونات منفصلة. تتيح معلمات ref أيضًا وصول تطبيقنا إلى المكونات الجديدة المحملة ديناميكيًا.

في إصدار اختبار واحد من تطبيق اللوحة ، لدي معالج الفاصل الزمني التالي:

 setInterval(() => { var refall = panelApp.$refs; // all named children that panels for ( var pname in refall ) { // in an object var pdata = refall[pname][0]; // off Vue translation, but it's there. pdata.temp1 = Math.round(Math.random()*100); // make thermos jump around. pdata.temp2 = Math.round(Math.random()*100); } },2000)

يوفر الكود القليل من الرسوم المتحركة ، ويغير موازين الحرارة بشكل عشوائي. تحتوي كل لوحة على مقياسين للحرارة ، ويسمح التطبيق للمستخدم بالاستمرار في إضافة اللوحات. (في الإصدار النهائي ، يجب التخلص من بعض اللوحات.) يتم الوصول إلى المراجع باستخدام panelApp.$refs ، وهو حقل ينشئه Vue مع إعطاء معلومات refs في علامة component .

إذن ، هذا ما تبدو عليه موازين الحرارة القافزة بشكل عشوائي في لقطة واحدة:

مجموعة من اللوحات المتحركة لنوع واحد من اللوحات (أو المكونات) تعرض موازين الحرارة.
مجموعة من اللوحات المتحركة لنوع واحد من اللوحات (أو المكونات). (معاينة كبيرة)

توصيل اللوحة بجهاز إنترنت الأشياء

لذا ، فإن الجزء الأخير من الكود هو اختبار setInterval يقوم بتحديث موازين الحرارة بقيم عشوائية كل ثانيتين. لكن ما نريد فعله هو قراءة بيانات حقيقية من أجهزة حقيقية. من أجل القيام بذلك ، سنحتاج إلى شكل من أشكال التواصل.

هناك طرق متنوعة. ولكن ، دعنا نستخدم MQTT وهو نظام رسائل pub / sub. يمكن لـ SPWA الخاص بنا الاشتراك في الرسائل من الأجهزة في أي وقت. عندما تتلقى هذه الرسائل ، يمكن لـ SPWA توجيه كل رسالة إلى معالج البيانات المناسب للوحة المعينة للجهاز المحدد في الرسالة.

لذلك ، ما نحتاج إلى فعله هو استبدال setInterval استجابة. وهذا سيكون للوحة واحدة. ربما نرغب في تعيين اللوحات إلى المعالجات أثناء تحميلها. والأمر متروك لخادم الويب لمعرفة أن التعيين الصحيح يتم تسليمه.

بمجرد أن يكون خادم الويب و SPWA جاهزان للتشغيل ، لم يعد خادم الويب بحاجة إلى رعاية الرسائل بين الصفحة والجهاز. يحدد بروتوكول MQTT خادم توجيه لمعالجة عام / فرعي. تم عمل عدد من خوادم MQTT. بعضها مفتوح المصدر. واحد شائع جدًا هو Mosquito ، وهناك عدد قليل تم تطويره أعلى Node.js.

عملية الصفحة بسيطة. يشترك SPWA في موضوع. أحد الإصدارات الجيدة للموضوع هو معرف MCU مثل عنوان MAC أو الرقم التسلسلي. أو يمكن أن يشترك SPWA في جميع قراءات درجات الحرارة. ولكن ، عندئذٍ ، يجب أن تقوم الصفحة بعمل تصفية الرسائل من جميع الأجهزة. يعد النشر في MQTT في الأساس بثًا أو بثًا متعددًا.

دعنا نلقي نظرة على كيفية تفاعل SPWA مع MQTT.

تهيئة MQTT على SPWA

هناك العديد من مكتبات العملاء للاختيار من بينها. واحد ، على سبيل المثال ، هو MQTT.js. آخر هو كسوف باهو. هناك المزيد بالطبع. دعنا نستخدم Eclipse Paho لأنه يحتوي على نسخة مخزنة من CDN. نحتاج فقط إلى إضافة السطر التالي إلى صفحتنا:

 <script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.min.js" type="text/javascript"></script>

يجب أن يتصل عميل MQTT بالخادم قبل أن يتمكن من إرسال الرسائل واستلامها. لذلك ، يجب أيضًا تضمين الأسطر التي تنشئ الاتصال في JavaScript. يمكننا إضافة وظيفة MQTTinitialize التي تقوم بإعداد العميل والاستجابات لإدارة الاتصال واستلام الرسائل.

 var messagesReady = false; var mqttClient = null; function MQTTinitialize() { mqttClient = new Paho.MQTT.Client(MQTTHostname, Number(MQTTPort), "clientId"); mqttClient.onMessageArrived = onMessageArrived; // connect the client mqttClient.connect({ onSuccess: () => { messagesReady = true; } }); // set callback handlers mqttClient.onConnectionLost = (response) => { // messagesReady = false; // if (response.errorCode !== 0) { console.log("onConnectionLost:"+response.errorMessage); } setTimeout(() => { MQTTinitialize() },1000); // try again in a second }; }

إعداد الاشتراك

عندما يكون الاتصال جاهزًا ، يمكن للعميل الاشتراك في قنوات الرسائل ، وإرسال الرسائل عليها ، وما إلى ذلك. يمكن لبعض الإجراءات فقط القيام بمعظم العمل الضروري لتوصيل اللوحات بمسارات MQTT.

بالنسبة للوحة SPWA ، يمكن استخدام لحظة الاشتراك لتأسيس الارتباط بين اللوحة والموضوع ، معرف MCU.

 function panelSubcription(topic,panel) { gTopicToPanel[topic] = panel; gPanelToTopic[panel] = topic; mqttClient.subscribe(topic); }

بالنظر إلى أن MCU تنشر حول موضوعها ، ستتلقى SPWA رسالة. هنا ، تم تفريغ رسالة Paho. وبعد ذلك يتم تمرير الرسالة إلى آليات التطبيق.

 function onMessageArrived(pmessage) { // var topic = pmessage.destinationName; var message = pmessage.payloadString; // var panel = gTopicToPanel[topic]; deliverToPanel(panel,message); }

لذا ، كل ما علينا فعله الآن هو إنشاء deliverToPanel والتي يجب أن تكون إلى حد ما مثل معالج الفاصل الزمني الذي كان لدينا من قبل. ومع ذلك ، فقد تم تحديد اللوحة بوضوح ، ويمكن فقط تحديث البيانات ذات المفاتيح المرسلة في رسالة معينة.

 function deliverToPanel(panel,message) { var refall = panelApp.$refs; // all named children that panels var pdata = refall[panel][0]; // off Vue translation, but it's there. var MCU_updates = JSON.parse(message); for ( var ky in MCU_updates ) { pdata[ky] = MCU_updates[ky] } }

تعتبر وظيفة deliverToPanel هذه مجردة بدرجة كافية للسماح بأي تعريف للوحة بأي عدد من نقاط البيانات للرسوم المتحركة.

إرسال الرسائل

لإكمال حلقة التطبيق بين MCU و SPWA ، نحدد وظيفة لإرسال رسالة.

 function sendPanelMessage(panel,message) { var topic = gPanelToTopic[panel]; var pmessage = new Paho.MQTT.Message(message); pmessage.destinationName = topic; mqttClient.send(pmessage); }

لا تقوم وظيفة sendPanelMessage بأكثر من إرسال الرسالة على نفس مسار الموضوع الذي يشترك فيه SPWA.

نظرًا لأننا نخطط لجعل أزرار الرموز مسؤولة عن جلب عدد معين من اللوحات لمجموعة واحدة من وحدات MCU ، سيكون هناك أكثر من لوحة واحدة للعناية بها. لكن ، نضع في اعتبارنا أن كل لوحة تتوافق مع MCU واحد ، لذلك لدينا تعيين واحد واحد ، والذي قد نستخدم خريطتي JavaScript للخريطة والعكس.

إذن ، متى نرسل رسائل؟ عادة ، سيرسل تطبيق اللوحة رسالة عندما يريد تغيير حالة MCU.

الحفاظ على حالة العرض (Vue) متزامنة مع الأجهزة

أحد الأشياء الرائعة في Vue هو أنه من السهل جدًا الحفاظ على تزامن نموذج البيانات مع نشاط المستخدم ، الذي يمكنه تحرير الحقول ، والنقر على الأزرار ، واستخدام أشرطة التمرير ، وما إلى ذلك. يمكن للمرء التأكد من أن تغييرات الزر والحقل سوف تنعكس على الفور في حقول بيانات المكونات.

لكننا نريد إجراء تغييرات لإطلاق الرسائل إلى MCU بمجرد حدوث التغييرات. لذلك ، نسعى للاستفادة من أحداث الواجهة التي قد تحكم Vue. نسعى للاستجابة لمثل هذا الحدث ، ولكن فقط بعد أن يصبح نموذج بيانات Vue جاهزًا بالقيمة الحالية.

لقد أنشأت نوعًا آخر من اللوحات ، هذه اللوحة ذات الزر ذي المظهر الفني إلى حد ما (ربما مستوحى من جاكسون بولوك). وقمت بتحويله إلى شيء بنقرته تشير إلى الحالة مرة أخرى إلى اللوحة التي تحتوي عليها. لم تكن هذه العملية بهذه البساطة.

الشيء الوحيد الذي طردني هو أنني نسيت بعض الشذوذ في إدارة SVG. حاولت أولاً تغيير سلسلة النمط بحيث يكون حقل display نمط CSS إما "لا شيء" أو "شيء". لكن المتصفح لم يعيد كتابة سلسلة الأنماط مطلقًا. ولكن ، نظرًا لأن ذلك كان مرهقًا ، فقد حاولت تغيير فئة CSS. هذا أيضا لم يكن له أي تأثير. ولكن ، هناك سمة visibility ، التي يتذكرها معظمنا من HTML القديم (ربما الإصدار 1.0) ، لكنها محدثة جدًا في SVG. وهذا يعمل بشكل جيد. كل ما كان علي فعله هو نشر حدث النقر فوق الزر.

صممت Vue خصائص لتنتشر في اتجاه واحد ، من الأب إلى الطفل. لذلك ، لتغيير البيانات في التطبيق ، أو في اللوحة ، عليك إرسال حدث تغيير إلى ولي الأمر. بعد ذلك ، يمكنك تغيير البيانات. يؤدي تغيير عنصر البيانات الذي يتحكم في الزر إلى قيام Vue بتحديث الخاصية التي تؤثر على رؤية عنصر SVG الذي اخترناه للإشارة إلى الحالة. هنا مثال:

أكثر من نوع واحد من اللوحات وأكثر من مثيل للرسوم المتحركة لكل نوع.
أخيرًا ، مجموعة من أنواع مختلفة من اللوحات لكل منها مثيلات مخصصة لفصل وحدات MCU. (معاينة كبيرة)

كل مثيل من لوحة الزر متعرج مستقل. لذلك ، بعضها قيد التشغيل والبعض الآخر مغلق.

يحتوي مقتطف SVG هذا على مؤشر أصفر غريب المظهر:

 <path :visibility="stateView" d="m -36.544616,12.266886 c 19.953088,17.062165 5.07961,-19.8251069 5.317463,8.531597 0.237853,28.356704 13.440044,-8.847959 -3.230451,10.779678 -16.670496,19.627638 14.254699,-2.017715 -11.652451,3.586456 -25.90715,5.60417 10.847826,19.889979 -8.095928,-1.546575 -18.943754,-21.436555 -1.177383,14.210702 -4.176821,-12.416207 -2.999438,-26.6269084 -17.110198,8.030902 2.14399,-8.927709 19.254188,-16.9586105 -19.075538,-8.0837048 9.448721,-5.4384245 28.52426,2.6452804 -9.707612,-11.6309807 10.245477,5.4311845 z" transform="translate(78.340803,6.1372042)" />

يتم ملء الرؤية بواسطة stateView ، وهو متغير محسوب يقوم بتعيين قيمة الحالة المنطقية لسلسلة من أجل SVG.

هذا هو قالب تعريف مكون اللوحة:

 <script type="text/x-template"> <div> <control-switch :state="bstate" v-on:changed="saveChanges" ></control-switch> <gauge :level="fluidLevel" ></gauge> </div> </script>

وهذا هو تعريف JavaScript للوحة Vue بأبنائها كمكونات فرعية:

 var widgdef = { data: function () { var currentPanel = { // at the top level, values controlling children bstate : true, fluidLevel : Math.round(Math.random()*100) } // return currentPanel }, template: '#mcu-control-panel-template', methods: { saveChanges: function() { // in real life, there is more specificity this.bstate = !this.bstate relayToMCU(this.name,"button",this.bstate) // to be defined } }, components: { 'control-switch' : { // the odd looking button props: ['state'], template: '#control-switch-template', // for demo it is in the page. computed: { // you saw this in the SVG above. stateView : function() { return ( this.state ) ? "visible" : "hidden" } }, methods : { // the button handler is in the SVG template at the top. stateChange : function () { // can send this.$emit('changed'); // tell the parent. See on the template instance } } }, 'gauge' : { // some other nice bit of SVG props: ['level'], template: '#gauge-template' } } }

لذلك ، تم الآن وضع آلية لزر واحد مضمن في لوحة. ويجب أن يكون هناك سبب لإخبار MCU بحدوث شيء ما. يجب استدعاؤه فورًا بعد تحديث حالة بيانات مكون اللوحة. دعنا نحددها هنا:

 function relayToMCU(panel,switchName,bstate) { var message = switchName + ':' + bstate // a on element parameter string. sendPanelMessage(panel,message) }

هناك تغيير في الحالة في طريقها إلى الأجهزة في سطرين فقط من التعليمات البرمجية.

لكن هذه حالة بسيطة إلى حد ما. يمكن اعتبار أي مفتاح بمثابة استدعاء وظيفي لقطعة من الأجهزة في العالم. لذلك ، قد تحتوي السلسلة على اسم المحول والعديد من عناصر البيانات الأخرى. لذلك ، يجب أن يكون لطريقة المكون التي تسجل التغيير بعض المعالجة المخصصة حتى تتمكن من جمع كل أجزاء البيانات الموجودة على اللوحة وإرسالها معًا في سلسلة أوامر واحدة. حتى سلسلة الأوامر بسيطة بعض الشيء. إذا كانت MCU صغيرة جدًا ، فقد يتعين ترجمة سلسلة الأمر إلى رمز. إذا كانت MCU تتمتع بقدر كبير من الإمكانيات ، فقد تكون سلسلة الأوامر في الواقع بنية JSON أو ربما جميع البيانات التي تستضيفها اللوحة.

في هذه المناقشة ، تحتوي الأزرار الموجودة على لوحة الرموز على اسم اللوحة المطلوب جلبها. قد يكون ذلك أيضًا مبسطًا إلى حد ما. يبدو من المنطقي أن هذه المعلمة يمكن أن تمثل أي لوحة قد يتم تخزينها في قواعد بيانات المؤسسات. لكن ، ربما تكون هذه صيغة ما. ربما ، يجب أن تلتف المعلومات حول اللوحة حول تعريف اللوحة الذي نتلقاها من الخادم. على أي حال ، يمكن توسيع الأساسيات بسهولة بمجرد إبعاد بعض الصداع عن الطريق ، مثل جعل SVG يستجيب للنقرات بشكل صحيح.

خاتمة

لقد حددت هذه المناقشة بعض الخطوات والقرارات الأساسية التي تؤدي إلى تحقيق تطبيق ويب صفحة واحدة (SPWA) يمكنه التفاعل مع أجهزة إنترنت الأشياء. نحن نعرف الآن كيفية الحصول على اللوحات من خادم الويب وتحويلها إلى واجهة MCU.

هناك الكثير من هذه المناقشة مع عدد غير قليل من المناقشات الأخرى التي قد تليها. البدء بـ Vue هو شيء يجب التفكير فيه. ولكن ، هناك قصة MCU بأكملها ، والتي تطرقنا إليها لفترة وجيزة فقط.

على وجه الخصوص ، من خلال اختيار MQTT كركيزة اتصال ، نفترض أن أجهزة إنترنت الأشياء على الطرف الآخر يمكن أن تحكم بطريقة ما بواسطة MQTT. لكن ، قد لا يكون هذا هو الحال دائمًا. في بعض الأحيان تكون هناك حاجة إلى بوابات إذا كانت MQTT ستتمكن من الوصول إلى جهاز به روابط تسلسلية أو Bluetooth. أو ربما كل ما يحتاجه المرء على صفحة الويب هو WebSockets. ومع ذلك ، استخدمنا MQTT كمثال لإظهار كيف يمكن لـ Vue تلقي البيانات وإرسالها مع الحفاظ على حالة بياناتها متزامنة مع الأجهزة.

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

أخيرًا ، في رأيي أن Vue تجعل تحديث البيانات عند الاستلام أمرًا رائعًا للغاية. لكن إرسال تغييرات الدولة ليس بالأمر السهل. لا يبدو أنه يجعل المهمة أبسط بكثير مما يمكن القيام به باستخدام Vanilla JavaScript. ولكن ، هناك طريقة وهذا منطقي.

ربما يمكن بناء مكتبة نظيفة لعمل مجموعة شاملة من المكونات لجميع اللوحات. تم الإشارة بإيجاز إلى عناصر إنشاء مثل هذه المكتبات وتخزينها في قاعدة بيانات. قد يلزم تطوير الأدوات التي تتجاوز مجرد إنشاء صور SVG. على أي حال ، من المحتمل أن يكون هناك العديد من الأشياء التي يمكن القيام بها للخطوات التالية.