يعد Ampelmännchen رمزًا مشهورًا في ألمانيا الشرقية، ويتم عرضه على إشارات مرور المشاة في كل زاوية من الشوارع. حتى أن هناك سلسلة متاجر للبيع بالتجزئة مقرها برلين مستوحاة من تصميمها.
لقد عثرت على مجموعة من إشارات أمبلمان المستعملة في سوق للسلع الرخيصة والمستعملة، وأردت التحكم بها من هاتفي. إذا كنت تريد أن تفعل الشيء نفسه، واصل القراءة!
تحذير صحي: يستخدم هذا المشروع طاقة التيار الكهربائي 220 فولت. أنا لست كهربائيا. اتبع هذه التعليمات على مسؤوليتك الخاصة.
كنت أرغب في بناء شيء بجمالية برلين ، وسيكون من الممتع لزوار منزلي أن يتفاعلوا معه. لسوء الحظ، انخفضت أعداد زوارنا بشدة هذا العام، ولكننا مازلنا نأمل في حدوث تفاعل كبير في عام 2021...؟
كل جهاز على شبكتك المحلية له عنوان IP خاص به (على سبيل المثال 192.168.1.20
). تتيح لك بعض أجهزة التوجيه، مثل FritzBox، أيضًا التصفح حسب أسماء المضيفين المحليين، بحيث يمكن الوصول إلى 192.168.1.20
أيضًا على mydevice.fritz.box
. بالنسبة لإشارة المرور، اسم مضيف الجهاز هو traffic-light
حتى نتمكن من زيارته على http://traffic-light.fritz.box
.
تطبيق الويب هو تطبيق بسيط للغاية وسريع الاستجابة يتكون من صفحة واحدة. يظهر:
الرمز موجود ضمن دليل /webapp. ليست هناك حاجة إلى أي تبعيات خارجية لأنها تعتمد فقط على ميزات المتصفح القياسية، مثل تحويل CSS وWebSockets وXHR. يمكنك معاينة التطبيق قيد التشغيل هنا على الرغم من أنه لن يتحكم في أي شيء، لأنك بالطبع لست متصلاً بشبكة LAN الخاصة بي. إذا قمت بزيارتها من الشبكة المحلية، على سبيل المثال http://traffic-light.fritz.box
فسوف تعمل بشكل كامل.
عند تحميل الصفحة، يقوم التطبيق بتقديم طلب GET للعثور على الحالة الحالية في /api/status
، ثم يفتح اتصال WebSocket بالخادم على المنفذ 81
. ستأتي تحديثات الحالة اللاحقة دائمًا عبر WebSocket، من أجل الحفاظ على مزامنة العديد من العملاء. في كل مرة يصل فيها حدث websocket، نطبق التغييرات على كائن state
عمومية واحد. بعد ذلك بوقت قصير، يطبق الأسلوب updateScreen()
هذه التغييرات على DOM.
عند بدء التشغيل، نكتشف أيضًا ما إذا كان المستخدم يستخدم جهازًا محمولاً أو سطح مكتب، للتعامل مع أحداث اللمس أو أحداث النقر. نحن في الواقع نستخدم حدث touchend
لإرسال الأوامر إلى الخادم، لأن هذا يؤدي بشكل أكثر موثوقية على iPhone X. وكان التمرير لأعلى من أسفل الشاشة للخروج من Safari يؤدي إلى إطلاق حدث touchstart
، مما يجعل من المستحيل الخروج من التطبيق دون تشغيله الضوء الأخضر!
وأخيرًا، نريد تقليل التحميل على الخادم حيثما أمكن ذلك. تذكر أن ESP8266 يعمل على معالج بسرعة 80 ميجا هرتز مع حوالي 50 كيلو بايت فقط من ذاكرة الوصول العشوائي. إنه ليس جهازًا سمينًا. لذلك عندما يكون المتصفح غير نشط، نقوم بفصل مقبس الويب. عند إعادة فتح علامة التبويب أو المتصفح، نتحقق مرة أخرى من الحالة ونعيد توصيل WebSocket.
ESP8266 مشغول بمعالجة طلبات واجهة برمجة التطبيقات ورمز التوقيت، لذلك لا يملك الموارد اللازمة لخدمة تطبيق الويب نفسه. كما أن إجراء تغييرات تجميلية على تطبيق الويب أمر صعب، إذا كنت بحاجة إلى الاتصال بالجهاز فعليًا في كل مرة أرغب في تطبيق تحديث.
يتبع ملف Index.html الخاص بتطبيق الويب مبدأ تطبيق الصفحة الواحدة الذي ينص على أن كل شيء يجب أن يتم عرضه بواسطة Javascript، مما يجعل محتوى HTML نفسه صغيرًا جدًا. مثل 550 بايت صغيرة. ويتم تحميل كل شيء آخر بواسطة متصفح العميل، دون الحاجة إلى إجراء المزيد من المكالمات إلى الخادم. لذلك تتم استضافة تطبيق الويب بالكامل على صفحات GitHub، وهي أداة استضافة مواقع ثابتة مجانية. يؤدي الضغط على /index.html
في الواقع إلى إنشاء طلب وكيل لصفحات GitHub، وإرجاع النتيجة إلى متصفح العميل.
يمكننا الآن تغيير أي شيء في تطبيق الويب، ولن يتأثر الخادم. عظيم! حسنًا ، تقريبًا ...
معظم التعليمات البرمجية لتطبيق الويب هذا موجودة في ملفات CSS وJS، وليس في index.html
نفسه. تقوم المتصفحات بتخزين أي ملفات تم تحميلها لفترة زمنية غير محددة قبل أن تعيد طلبها. إذا لم يتغير ملف Index.html، ولكننا قمنا بنشر إصدار JS جديد، فكيف سيعرف عملاؤنا أنهم بحاجة إلى تحميل إصدار JS الجديد؟
عندما ندفع أي إصدار جديد من التعليمات البرمجية الخاصة بنا إلى فرع git master
، يتم تشغيل إجراء GitHub، الذي ينفذ النشر إلى صفحات GitHub حيث يتم تقديم الصفحة فعليًا للجمهور. تكمن الحيلة هنا في إلحاق اللاحقة ?version=latest
بنهاية ملفات CSS وJS الخاصة بنا، في ملف index.html
. قبل نسخ المحتوى إلى فرع gh-pages
، يستخدم الإجراء الأمر sed
لاستبدال " latest
" بقيمة المتغير $GITHUB_SHA
، والذي يعد في الواقع آخر معرف التزام في الفرع master
. (على سبيل المثال قيمة مثل b43200422c4f5da6dd70676456737e5af46cb825
).
بعد ذلك، في المرة التالية التي يزور فيها العميل تطبيق الويب، سيرى المتصفح قيمة جديدة ومختلفة بعد ?version=
، ويطلب ملف JS أو CSS الجديد والمحدث، والذي لن يتم تخزينه مؤقتًا بالفعل.
راجع طريقة setup(void)
في traffic-light-controller.ino
وقسم Arduino Code لمعرفة كيفية عمل ذلك عمليًا.
قررت استخدام كل من REST وWebSockets جنبًا إلى جنب. يتم استخدام REST في الغالب من قبل العملاء للتحكم في الخادم. يتم استخدام WebSockets لبث معلومات الحالة للعملاء. هناك العديد من الأدوات مثل Postman التي تتيح لك تجربة REST API بسهولة، لذلك وجدت هذا أكثر ملاءمة.
HTTP API: راجع وثائق Swagger هنا.
WebSocket API: يرسل اتصال websocket نقاط JSON التي يستخدمها تطبيق الويب لتحديث حالته الداخلية. يمكن أن يحتوي حدث websocket على حقل واحد أو أكثر للتحديث. قد يبدو المثال الذي يحتوي على معلومات بيئية كما يلي:
{
"redTemperature" : 21.6 ,
"greenTemperature" : 22.7 ,
"greenHumidity" : 55 ,
"redHumidity" : 59
}
لا يتم حاليًا إرسال أي بيانات من العميل إلى الخادم عبر websocket، على الرغم من أن هذا ممكن.
كود الاردوينو موجود في ملف واحد يتضمن تعليقات توضيحية.
يبدأ بمجموعة من التعريفات للمواقع الدبوسية وواردات المكتبة والقيم المشفرة لأشياء مثل أنواع محتوى HTTP وقيم رمز الاستجابة. يلي ذلك مجموعة من المتغيرات التي يمكن أن تتغير في وقت التشغيل، جميعها مسبوقة بشرطات سفلية. تتم أيضًا تهيئة بعض الكائنات هنا، بما في ذلك تلك الخاصة بخادم الويب وخادم مقبس الويب وعميل WiFi وأجهزة استشعار درجة الحرارة. تتم صيانة "ساعة النظام" بواسطة حقل _currentMillis
.
بعد التشغيل، يتم تشغيل طريقة setup(void)
. بعد إجراء بعض عمليات إعداد الدبوس، يقوم بإنشاء التعيينات اللازمة لنقاط نهاية REST، ويبدأ الخوادم في الاستماع لطلبات العميل. طريقة loop(void)
هي المسؤولة عن كل شيء آخر. تقوم كل دورة بمعالجة أي طلبات ويب معلقة، وتحديث دورة الإيقاع، وقراءة المستشعرات إذا لزم الأمر. إذا كنا في وضع الحفلة، فسيتم ضبط حالة الفلاش/النبض الحالية.
يتم ترميز الإيقاع (لوضع الحفلة) لتشغيل التسلسل في الحقل RHYTHM_PATTERN
، ولكن من الناحية النظرية يمكن تغييره في وقت التشغيل إلى أي شيء آخر. في كل مرة نستدعي فيها طريقة rhythm()
، نستخدم قيم _bpm
و_ _currentMillis
الحالية لتحديد الموضع الذي يجب أن نكون فيه في النمط. يتم تخزين هذا في حقل _rhythmStep
.
أثناء نمط الإيقاع، هناك فترات يتم فيها إيقاف تشغيل كلا المرحلات فعليًا. ولكن نظرًا لأن المصابيح عبارة عن مصابيح متوهجة، فإنها لا تبدأ أو تتوقف عن إصدار الضوء على الفور. يبدو أن المصابيح تستغرق حوالي 1.7 ثانية للتشغيل أو الإيقاف الكامل. لذلك، من خلال إضافة فترة داخل النمط حيث يتم إيقاف تشغيل كليهما، ننتهي بنمط نبض لطيف حيث تسخن المصابيح وتبرد.
في طريقة partyFlash()
، نحصل على عنصر النمط الذي من المفترض أن يتم عرضه حاليًا (أو سيتم إيقاف تشغيل كليهما) ونستدعي lightSwitch(...)
مع المعلمات المناسبة. lightSwitch(...)
بدوره باستدعاء sendToWebSocketClients(...)
بحيث يتم تحديث جميع العملاء المتصلين إلى الحالة الجديدة.
إذا قام المستخدم ببساطة بالنقر فوق أحد الأضواء لتشغيله أو إيقاف تشغيله، فستكون العملية مشابهة، ولكن يتم التعامل معها كطلب REST. يتم استدعاء إحدى طرق handleX
، والتي تتحقق من صحة الطلب، وتقوم بدورها باستدعاء lightSwitch(...)
.
وفي فترات زمنية أقل، نقوم بفحص درجة حرارة الحافظتين، ونرسل ذلك أيضًا عبر WebSocket إلى جميع العملاء. يُستخدم هذا حاليًا لأغراض إعلامية فقط ولكن يمكن استخدامه لتعطيل الأضواء عندما تتجاوز درجة الحرارة بعض حدود الأمان.
الائتمان لmrcosta لمساعدته في مراجعة هذه المقالة.