تطوير الأجهزة الذكية باستخدام مثال وحدة التحكم الأرضية الساخنة على ESP8266

أريد مشاركة تجربتي في تطوير جهاز ذكي. في هذا المنشور ، سأصف برامج الأجهزة (لفترة وجيزة) وبرامج (بمزيد من التفاصيل).

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

الأجهزة


كوحدة تحكم ، تم اختيار ESP8266 (WeMos D1 mini) ، كـ لديه واي فاي على متن الطائرة. بدلاً من ESP8266 ، يمكن استخدام أي وحدة تحكم أو كمبيوتر دقيق آخر - ستبقى الأفكار العامة دون تغيير ، والشيء الرئيسي هو أنه يمكن نشر خادم WEB مع دعم مقابس WEB على النظام المحدد. كما تم استخدام ما يلي في المشروع:

  • RTC: DS3231 - من الضروري تحديد يوم الأسبوع والوقت الحالي. تم تصميم المشروع كجهاز مستقل يمكن أن يعمل بدون الإنترنت ، لذا فإن NTP غير مناسب.
  • أجهزة استشعار درجة الحرارة اللاسلكية: NoName ، 433MHz ، من محطة الطقس الصينية - حل جاهز ، تعمل على البطاريات. ماذا تحتاج ايضا؟ ولكن من الضروري ألا تكون فترة نقل البيانات ثابتة. تكمن المشكلة في أن فترة الإرسال 35 ثانية ولا تسبح كثيرًا. وهناك حالات تتداخل فيها إشارات مستشعرين. في هذه الحالة ، ينقطع جهاز استشعار واحد أو اثنين من النظام لفترة من الوقت. يمكن حل المشكلة باستخدام أجهزة استشعار مماثلة ، حيث يؤدي تبديل القنوات أيضًا إلى تغيير فترة إرسال البيانات.
  • جهاز استقبال 433 ميجا هرتز: Rxb6 - مراجعات الإنترنت والخبرة الشخصية ليست جهاز استقبال سيئ.
  • أجهزة استشعار درجة الحرارة السلكية: DS18B20 - مريحة للغاية حيث لا تحتاج إلى معرفة عدد أجهزة الاستشعار مقدمًا.
  • 1Wire bus master: DS2482-100 - 1Wire Protocol حساس جدًا للتوقيت ، وبالتالي فإن جميع تطبيقات تأخير استخدام ناقل البرنامج الرئيسي ، والتي ليست جيدة جدًا لتعدد المهام. باستخدام هذه الشريحة ، يمكنك الاستفادة من ناقل 1Wire والتخلص من عيوبه عن طريق بث 1Wire <-> i2c. يحتوي بروتوكول i2c على خط التزامن ، والذي لا يعتبر مهمًا بالنسبة للتوقيتات وغالبًا ما يتم تنفيذه في الأجهزة في وحدات التحكم.
  • مؤقت المراقبة: TPL5000DGST - وقت التشغيل المستمر ليس مهمًا جدًا لهذا المشروع ، ولكن إمكانية الوصول مهمة جدًا. يحتوي ESP8266 على جهاز توقيت مدمج للمراقبة. ولكن كما أظهرت الممارسة ، لا تزال هناك أحيانًا مواقف لا يمكن فيها التأقلم ويتجمد النظام. تم تصميم موقت مراقبة الأجهزة الخارجية للتعامل مع حالات الطوارئ. تم تكوينه لمدة 64 ثانية. متصل بالساق TX - أثناء التشغيل ، يكتب النظام باستمرار معلومات تصحيح الأخطاء إلى Serial ، ويشير نقص النشاط لأكثر من دقيقة واحدة إلى تعليق النظام.
  • موسع المنفذ: 74HC595 - يتطلب استخدام هذا الموسع 4 أرجل من وحدة التحكم - ثلاثة لنقل الحالة وواحدة بحيث لا تنقر المرحلات عند تطبيق الطاقة. في المرة القادمة التي سأستخدم PCF8574 - لا يزال ناقل i2c مستخدمًا ، أي ليس هناك حاجة إلى أرجل MCU إضافية ويتم تعيين المخرجات 1 عند تطبيق الطاقة.
  • وحدة الترحيل: NoName، 8-channel، 5V - لا يوجد ما يقال ، باستثناء أن التتابع قيد التشغيل عند مستوى منخفض عند مدخلات الوحدة. لا يسمح بمرحلات الحالة الصلبة في هذا المشروع ، مثل يجب تبديل جهات اتصال الغلاية عن طريق الاتصال الجاف - بشكل عام ، لا أعرف الجهد والتيار المباشر أو التيار المتناوب على جهات الاتصال.

نظام تشغيل


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

نظام الملفات


يستخدم المشروع SPIFFS ، يبدو أن كل شيء واضح هنا ، هذه هي أسهل طريقة. لسهولة الوصول إلى الملفات الموجودة على الجهاز من الخارج ، أستخدم مكتبة nailbuster / esp8266FTPServer.

نظام تخصيص الوقت CPU


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

  • التنفيذ الدوري للوظيفة ، مع فاصل زمني محدد. مثال على تهيئة المؤقت:

    Timers.add(doLoop, 6000, F("OneWireSensorsClass::doLoop")); //   –   
  • تنفيذ واحد للدالة بعد فترة زمنية محددة. على سبيل المثال ، يتم إجراء فحص متأخر لشبكات WiFi بهذه الطريقة:

     Timers.once([]() { WiFi.scanNetworks(true);}, 1); 

وبالتالي ، تبدو وظيفة الحلقة كما يلي:

 void loop(void) { ESP.wdtFeed(); Timers.doLoop(); CPULoadInfo.doLoop(); } 

من الناحية العملية ، تحتوي وظيفة الحلقة على عدد قليل من الأسطر ، والتي سيتم وصفها أدناه.
يتم إرفاق قائمة بفئة المؤقتات.

محاسبة الوقت CPU


وظيفة الخدمة التي ليس لها تطبيق عملي. ومع ذلك ، فهي كذلك. ينفذها المفرد CPULoadInfo. عند تهيئة الكائن ، يتم قياس عدد تكرارات الحلقة الفارغة لفترة زمنية قصيرة:

 void CPULoadInfoClass::init() { uint32_t currTime = millis(); //      1 while ((millis() - currTime) < 10) { delay(0); MaxLoopsInSecond++; } MaxLoopsInSecond *= 100; } 

بعد ذلك ، نحسب عدد استدعاءات إجراءات التكرار في الثانية ، ونحسب حمل المعالج في المئة ونحفظ البيانات في المخزن المؤقت:

 void CPULoadInfoClass::doLoop() { static uint32_t prevTime = 0; uint32_t currTime = millis(); LoopsInSecond++; if ((currTime - prevTime) > 1000) { memmove(CPULoadPercentHistory, &CPULoadPercentHistory[1], sizeof(CPULoadPercentHistory) - 1); int8_t load = ((MaxLoopsInSecond - LoopsInSecond) * 100) / MaxLoopsInSecond; CPULoadPercentHistory[sizeof(CPULoadPercentHistory) - 1] = load; prevTime = currTime; LoopsInSecond = 0; } } 

يتيح لك استخدام هذا الأسلوب الحصول على نفس استخدام المعالج من خلال كل مؤشر ترابط فردي (إذا قمت بتوصيل هذا النظام الفرعي بفئة المؤقتات) ، ولكن كما قلت - لا أرى أي تطبيق عملي لهذا.

نظام الإدخال والإخراج


للتواصل مع المستخدم ، يتم استخدام واجهة UART-USB و WEB. أفكر في UART لست بحاجة إلى التحدث بالتفصيل. الشيء الوحيد الذي يستحق الانتباه إليه هو الراحة والتوافق مع غير ESP يتم تنفيذ وظيفة serialEvent ():

 void loop(void) { // … if (Serial.available()) serialEvent(); // … } 

مع واجهة WEB ، كل شيء أكثر إثارة للاهتمام. نحن نكرس قسم منفصل لذلك.

واجهة WEB


في حالة الأجهزة الذكية ، في رأيي ، فإن واجهة WEB هي الحل الأكثر سهولة في الاستخدام.

أعتبر استخدام شاشة متصلة بالجهاز ممارسة قديمة - من المستحيل إنشاء واجهة بسيطة ومريحة وجميلة عند استخدام شاشة صغيرة ومجموعة محدودة من الأزرار.

إن استخدام برامج محددة للتحكم في الجهاز يفرض قيودًا على المستخدم ، ويضيف الحاجة إلى تطوير ودعم هذه البرامج ، كما يتطلب من المطور الاهتمام بتسليم هذه البرامج إلى الأجهزة الطرفية للمستخدم. بطريقة جيدة ، يجب نشر التطبيق في متاجر تطبيقات Google ، و Apple ، و Windows ، ومتوفر أيضًا في مستودعات Linux في شكل حزم deb و rpm - وإلا ، فقد يكون الوصول إلى واجهة الجهاز صعبًا بالنسبة لجزء من الجمهور.

يتوفر الوصول إلى واجهة WEB للجهاز من أي نظام تشغيل - Linux و Windows و Android و MacOS ، على سطح المكتب أو الكمبيوتر المحمول أو الجهاز اللوحي أو الهاتف الذكي - لمجرد الحصول على متصفح. بالطبع ، يجب على مطور واجهة WEB أن يأخذ في الاعتبار ميزات الأجهزة المختلفة ، ولكن هذا يتعلق بشكل أساسي بالحجم والدقة. يتم توفير الوصول إلى واجهة WEB لجهاز ذكي في منزل / شقة / كوخ بسهولة من الخارج عبر الإنترنت - من الصعب الآن تخيل منزل / شقة يوجد بها أجهزة ذكية ولا يوجد فيها جهاز توجيه وإنترنت ، وفي جهاز التوجيه يتم تكوين هذا الوصول ببضع نقرات (لأولئك الذين خارج الموضوع تمامًا ، ستساعد الكلمات الرئيسية - "إعادة توجيه المنفذ" و "DNS الديناميكي"). في حالة الإقامة الصيفية ، يمكن توفير الوصول باستخدام جهاز توجيه 3G.

لتنفيذ واجهة WEB ، مطلوب خادم WEB. أنا أستخدم مكتبة me-no-dev / ESPAsyncWebServer. توفر هذه المكتبة الوظائف التالية:

  • عودة المحتوى الثابت ، بما في ذلك مع دعم ضغط gzip. يتم دعم الدلائل الافتراضية ، مع إمكانية تحديد ملف رئيسي (والذي عادة ما يكون index.htm) لكل دليل.
  • تعيين وظائف رد الاتصال لعناوين URL مختلفة بناءً على نوع الطلب (GET ، POST ، ...)
  • دعم مقابس WEB على نفس المنفذ (يهم عند إعادة توجيه المنفذ).
  • إذن BASIC. علاوة على ذلك ، يتم تعيين التفويض بشكل فردي لكل عنوان URL. هذا مهم لأن على سبيل المثال ، Google Chrome ، عند إنشاء اختصار صفحة على الشاشة الرئيسية ، يطلب رمزًا وملف بيان ولا ينقل بيانات التفويض. لذلك ، يتم وضع بعض الملفات في دليل ظاهري ويتم تعطيل الترخيص لهذا الدليل.

نظام تشغيل خدمات HTTP


في المشروع الحالي ، يتم تنفيذ جميع إعدادات نظام التشغيل باستخدام خدمات HTTP. خدمة HTTP هي وظيفة صغيرة مستقلة لاسترجاع / تعديل البيانات متاحة عبر HTTP. بعد ذلك ، ضع في اعتبارك قائمة بهذه الخدمات.

النجدة


تنفيذ أي قائمة أوامر ، أعتقد أنه من الصحيح أن تبدأ بتنفيذ فريق المساعدة. أدناه هو كتلة تهيئة خادم WEB:

 void HTTPserverClass::init() { //SERVER INIT help_info.concat(F("/'doc_hame.ext': load file from server. Allow methods: HTTP_GET\n")); AsyncStaticWebHandler& handler = server.serveStatic("na/", SPIFFS, "na/"); serveStaticHandlerNA = &handler; //       server.serveStatic("/", SPIFFS, "/"); //    //info //       help_info.concat(F("/info: get system info. Allow methods: HTTP_GET\n")); server.on("/info", HTTP_GET, handleInfo); … server.on("/help", HTTP_GET, [](AsyncWebServerRequest *request) { request->send(200, ContentTypesStrings[ContentTypes::text_plain], help_info.c_str()); }); //    setAuthentication(ConfigStore.getAdminName(), ConfigStore.getAdminPassword()); DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*"); //  -  //   server.begin(); //       DEBUG_PRINT(F("HTTP server started")); } 

لماذا أحتاج إلى نظام مساعدة ، أعتقد أنه لا يستحق أن نقول. يؤجل بعض المطورين تنفيذ نظام المساعدة لوقت لاحق ، ولكن هذا "لاحقًا" لا يحدث عادةً. من الأسهل تنفيذه في بداية المشروع واستكماله أثناء تطوير المشروع.
في مشروعي ، يتم أيضًا عرض قائمة بالخدمات المحتملة مع ظهور خطأ 404 - لم يتم العثور على الصفحة. تنفذ حاليا الخدمات التالية:

http://tc-demo.vehs.ru/help

 /'doc_hame.ext': load file from server. Allow methods: HTTP_GET /info: get system info. Allow methods: HTTP_GET /time: get time as string (eg: 20140527T123456). Allow methods: HTTP_GET /uptime: get uptime as string (eg: 123D123456). Allow methods: HTTP_GET /rtc: set RTC time. Allow methods: HTTP_GET, HTTP_POST /list ? [dir=...] & [format=json]: get file list as text or json. Allow methods: HTTP_GET /edit: edit files. Allow methods: HTTP_GET, HTTP_PUT, HTTP_DELETE, HTTP_POST /wifi: edit wifi settings. Allow methods: HTTP_GET, HTTP_POST /wifi-scan ? [format=json]: get wifi list as text or json. Allow methods: HTTP_GET /wifi-info ? [format=json]: get wifi info as text or json. Allow methods: HTTP_GET /ap: edit soft ap settings. Allow methods: HTTP_GET, HTTP_POST /user: edit user settings. Allow methods: HTTP_GET, HTTP_POST /user-info ? [format=json]: get user info as text or json. Allow methods: HTTP_GET /update: update flash. Allow methods: HTTP_GET, HTTP_POST /restart: restart system. Allow methods: HTTP_GET, HTTP_POST /ws: web socket url. Allow methods: HTTP_GET /help: list allow URLs. Allow methods: HTTP_GET 

كما ترى ، في قائمة الخدمات لا توجد خدمات تطبيق. ترتبط جميع خدمات HTTP بنظام التشغيل. تقوم كل خدمة بمهمة واحدة صغيرة. علاوة على ذلك ، إذا كانت الخدمة تتطلب إدخال أي بيانات ، فإن GET ، عند الطلب ، تُرجع نموذج إدخال أضيق الحدود:

 #ifdef USE_RTC_CLOCK help_info.concat(F("/rtc: set RTC time. Allow methods: HTTP_GET, HTTP_POST\n")); const char* urlNTP = "/rtc"; server.on(urlNTP, HTTP_GET, [](AsyncWebServerRequest *request) { DEBUG_PRINT(F("/rtc")); request->send(200, ContentTypesStrings[ContentTypes::text_html], String(F("<head><title>RTC time</title></head><body><form method=\"post\" action=\"rtc\"><input name=\"newtime\" length=\"15\" placeholder=\"yyyyMMddThhmmss\"><button type=\"submit\">set</button></form></body></html>"))); }); server.on(urlNTP, HTTP_POST, handleSetRTC_time); #endif // USE_RTC_CLOCK 



في وقت لاحق يتم استخدام هذه الخدمة في واجهة أجمل:



البرامج التطبيقية


أخيراً وصلنا إلى النقطة التي تم إنشاء النظام من أجلها. وهي - لتنفيذ المهمة التطبيقية.

يجب أن يتلقى أي تطبيق البيانات المصدر ومعالجتها وإنتاج النتيجة. من الممكن أيضًا أن يقوم النظام بالإبلاغ عن الحالة الحالية.

البيانات المصدر لوحدة التحكم في التدفئة تحت البلاط هي:

  • بيانات المستشعر - النظام غير مرتبط بأجهزة استشعار محددة. يتم إنشاء معرف فريد لكل مستشعر. بالنسبة لأجهزة الاستشعار اللاسلكية ، يتم تبطين معرّفها بأصفار إلى 16 بت ؛ أما بالنسبة لأجهزة استشعار 1Wire ، يتم حساب CRC16 بناءً على معرفها الداخلي ويتم استخدامه كمعرف جهاز استشعار. وبالتالي ، تحتوي جميع أجهزة الاستشعار على معرفات بطول 2 بايت.
  • البيانات المتعلقة بمناطق التسخين - عدد المناطق غير ثابت ، والحد الأقصى لعدد محدود بواسطة وحدة الترحيل المستخدمة. نظرًا لهذا القيد ، تم تطوير واجهة WEB أيضًا.
  • درجة الحرارة المستهدفة والجدول الزمني - لقد حاولت إجراء الإعدادات الأكثر مرونة ، ويمكنك إنشاء العديد من أنظمة التدفئة ، ويمكنك أيضًا تعيين مخطط الإعدادات الخاص بك لكل منطقة.

وبالتالي ، هناك عدد من الإعدادات التي يجب تعيينها بطريقة ما ، وهناك عدد من المعلمات التي يبلغ عنها النظام على أنها الحالة الحالية.
للتواصل بين وحدة التحكم والعالم الخارجي ، قمت بتطبيق مترجم الأوامر الذي سمح لي بتنفيذ كل من التحكم في وحدة التحكم وتلقي بيانات الحالة. يتم إرسال الأوامر إلى وحدة التحكم في شكل قابل للقراءة البشرية ، ويمكن إرسالها عبر مقبس UART أو WEB (إذا كنت ترغب في ذلك ، يمكنك تنفيذ دعم البروتوكولات الأخرى ، على سبيل المثال telnet).
يبدأ سطر الأوامر بالحرف "#" وينتهي بحرف فارغ أو حرف سطر جديد. تتكون جميع الأوامر من اسم أمر ومعامل ، مفصولة بنقطتين. بالنسبة لبعض الأوامر ، يكون المعامل اختياريًا ، وفي هذه الحالة ، لا يتم تحديد النقطتين والمعامل. يتم فصل الأوامر الموجودة في السطر بفاصلة. على سبيل المثال:

 #ZonesInfo:1,SensorsInfo 

وبالطبع ، تبدأ قائمة الأوامر بالأمر Help ، الذي يعرض قائمة بجميع الأوامر الصالحة (للراحة ، تبدأ الأوامر المرسلة بـ ">" بدلاً من "#"):

 >help Help SetZonesCount Zone SetName SetSensor ... LoadCfg SaveCfg #Cmd:Help,CmdRes:Ok 

ميزة تنفيذ مترجم الأوامر هي أن المعلومات حول نتيجة تنفيذ الأمر يتم إصدارها أيضًا في شكل أمر أو مجموعة من الأوامر:

 >help#Cmd:Help,CmdRes:Ok >zone:123 #Cmd:Zone,Value:123,CmdRes:Error,Error:Zone 123 not in range 1-5 >SchemasInfo #SchemasCount:2 #Schema:1,Name:,DOWs:0b0000000 #Schema:2,Name:,DOWs:0b0000000 #Cmd:SchemasInfo,CmdRes:Ok 

على جانب عميل WEB ، يتم أيضًا تنفيذ shell يقبل هذه الأوامر ويحولها إلى عرض رسومي. على سبيل المثال:

 >zonesInfo:3 #Zone:3,Name:,Sensor:0x5680,Schema:1,DeltaT:-20 #Cmd:ZonesInfo,CmdRes:Ok 

أرسلت واجهة WEB طلبًا إلى وحدة التحكم حول المنطقة رقم 3 ، واستجابة لذلك ، استقبلت اسم المنطقة ومعرف المستشعر المرتبط بالمنطقة ومعرف الدائرة المخصصة للمنطقة وتصحيح درجة الحرارة للمنطقة. لا تفهم القشرة الأرقام الكسرية ، لذلك تنتقل درجة الحرارة بعشر درجة ، أي 12.3 درجة هي 123 أعشار.

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

 #sensor:0x5A20,type:w433th,battery:1,button_tx:0,channel:0,temperature:228,humidity:34,uptime_label:130308243,time_label:20180521T235126 

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

 #Zone:2,TargetTemp:220,CurrentTemp:228,Error:Ok 

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

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

الخلاصة


باستخدام نهج مماثل ، وهي:

  • فصل البرنامج إلى نظام التشغيل وبرنامج التطبيق
  • تنفيذ إعدادات نظام التشغيل في شكل خدمات HTTP أضيق الحدود
  • فصل منطق النظام عن عرض البيانات
  • استخدام بروتوكولات الاتصال البشرية المقروءة

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



كما ترى ، في هذا المشروع ترتبط الصفحات الثلاث الأولى فقط من الواجهة مباشرة بالتطبيق ، والباقي شبه عالمية.

في هذا المنشور ، أصف رأيي فقط في بناء الأجهزة الذكية ، ولا أدعي بأي حال من الأحوال أنها الحقيقة المطلقة.

لمن هذا الموضوع مثير للاهتمام - اكتب ، ربما أكون مخطئًا بشأن شيء ما ، ولكن ربما تكون بعض التفاصيل منطقية لوصف بمزيد من التفاصيل.

ماذا حدث في النهاية: الفاسكو. قصة إنترنت الأشياء واحدة محلية الصنع

Source: https://habr.com/ru/post/ar412889/


All Articles