Pengembangan perangkat pintar menggunakan contoh pengontrol lantai yang dipanaskan pada ESP8266

Saya ingin berbagi pengalaman dalam mengembangkan perangkat pintar. Dalam publikasi ini, saya akan menjelaskan perangkat keras (singkat) dan perangkat lunak (lebih terinci) perangkat lunak.

Pengontrol dirancang untuk menganalisis pembacaan sensor (kabel dan nirkabel) dan mempertahankan suhu yang diatur (termasuk jadwal, termasuk hari-hari dalam seminggu) di setiap zona individu dengan menghidupkan / mematikan boiler dan mengendalikan loop pemanas lantai air menggunakan kepala termal pada kolektor.

Perangkat keras


Sebagai pengontrol, ESP8266 (WeMos D1 mini) dipilih, sebagai memiliki wifi di kapal. Alih-alih ESP8266, pengontrol atau mikrokomputer lain dapat digunakan - ide umum akan tetap tidak berubah, hal utama adalah bahwa server WEB dengan dukungan untuk soket WEB dapat digunakan pada sistem yang dipilih. Berikut ini juga digunakan dalam proyek:

  • RTC: DS3231 - perlu untuk menentukan hari dalam seminggu dan waktu saat ini. Proyek ini disusun sebagai perangkat yang berdiri sendiri yang dapat bekerja tanpa internet, sehingga NTP tidak cocok.
  • Sensor suhu nirkabel: NoName, 433MHz, dari stasiun cuaca China - solusi turnkey, mereka bekerja pada baterai. Apa lagi yang kamu butuhkan? Tetapi perlu bahwa periode transfer data tidak tetap. Masalahnya adalah bahwa periode transmisi adalah 35 detik dan tidak banyak berenang. Dan ada situasi ketika sinyal dua sensor tumpang tindih. Dalam hal ini, satu atau dua sensor keluar dari sistem untuk sementara waktu. Masalahnya dapat diselesaikan dengan menggunakan sensor yang sama, di mana perpindahan saluran juga mengubah periode transmisi data.
  • Penerima 433MHz: Rxb6 - Ulasan internet dan pengalaman pribadi bukanlah penerima yang buruk.
  • Sensor suhu kabel: DS18B20 - sangat praktis karena Anda tidak perlu tahu jumlah sensor sebelumnya.
  • 1Wire bus master: DS2482-100 - 1Wire protocol sangat sensitif terhadap pengaturan waktu, oleh karena itu semua implementasi penundaan penggunaan master bus program, yang tidak terlalu baik untuk multitasking. Dengan menggunakan chip ini, Anda dapat memanfaatkan bus 1Wire dan menyingkirkan kekurangannya dengan menyiarkan 1Wire <-> i2c. Protokol i2c memiliki jalur sinkronisasi, karena itu tidak penting untuk pengaturan waktu dan sering diimplementasikan dalam perangkat keras dalam pengontrol.
  • Timer Watchdog: TPL5000DGST - uptime terus-menerus tidak begitu penting untuk proyek ini, namun aksesibilitas sangat penting. ESP8266 memiliki pengawas waktu built-in. Tetapi seperti yang ditunjukkan oleh praktik, kadang-kadang masih ada situasi di mana ia tidak dapat mengatasi dan sistem membeku. Timer pengawas perangkat keras eksternal dirancang untuk menangani situasi darurat. Dikonfigurasi untuk penundaan selama 64 detik. Terlampir pada leg TX - selama operasi, sistem terus-menerus menulis informasi debug ke Serial dan kurangnya aktivitas selama lebih dari satu menit menunjukkan hang sistem.
  • Port expander: 74HC595 - penggunaan expander ini memerlukan 4 kaki pengontrol - tiga untuk mentransmisikan status dan satu agar relay tidak berbunyi klik saat daya diterapkan. Lain kali saya akan menggunakan PCF8574 - bus i2c masih digunakan, mis. tidak diperlukan kaki MCU tambahan dan output 1 ditetapkan saat daya diterapkan.
  • Modul relai: NoName, 8-channel, 5V - tidak ada yang bisa dikatakan, kecuali bahwa relai dihidupkan pada tingkat rendah pada input modul. Relai keadaan padat tidak diizinkan dalam proyek ini, karena Kontak boiler harus diaktifkan oleh kontak kering - secara umum, saya tidak tahu tegangan dan arus bolak-balik pada kontak.

Sistem operasi


Sistem operasi adalah semua perangkat lunak yang memastikan operabilitas program aplikasi. Sistem operasi juga merupakan lapisan antara perangkat keras dan program aplikasi, menyediakan antarmuka tingkat tinggi untuk mengakses sumber daya perangkat keras. Dalam kasus ESP, komponen sistem operasi dapat dipertimbangkan:

Sistem file


Proyek ini menggunakan SPIFFS, semuanya tampak jelas di sini, ini adalah cara termudah. Untuk akses mudah ke file di perangkat dari luar, saya menggunakan perpustakaan nailbuster / esp8266FTPSver.

Sistem alokasi waktu CPU


Ini adalah salah satu fungsi utama sistem operasi dan ESP tidak akan menjadi pengecualian. Untuk eksekusi paralel dari berbagai aliran algoritma, Timers objek global (singleton) bertanggung jawab. Kelasnya cukup sederhana dan menyediakan fungsionalitas berikut:

  • Eksekusi fungsi secara berkala, dengan interval yang ditentukan. Inisialisasi pengatur waktu contoh:

    Timers.add(doLoop, 6000, F("OneWireSensorsClass::doLoop")); //   –   
  • Eksekusi tunggal fungsi setelah periode waktu tertentu. Misalnya, pemindaian jaringan WiFi yang tertunda dilakukan dengan cara ini:

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

Dengan demikian, fungsi loop terlihat seperti ini:

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

Dalam praktiknya, fungsi loop berisi beberapa baris lagi, yang akan dijelaskan di bawah ini.
Daftar kelas Timers terlampir.

Akuntansi waktu CPU


Fungsi layanan yang tidak memiliki aplikasi praktis. Namun demikian, dia. Diimplementasikan oleh CPULoadInfo tunggal. Ketika objek diinisialisasi, jumlah iterasi dari loop kosong diukur untuk periode waktu yang singkat:

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

Kemudian, kami menghitung jumlah panggilan prosedur loop per detik, kami menghitung beban prosesor dalam persen dan menyimpan data ke buffer:

 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; } } 

Menggunakan pendekatan ini memungkinkan Anda untuk mendapatkan penggunaan prosesor yang sama oleh masing-masing utas individu (jika Anda menghubungkan subsistem ini dengan kelas Timers), tetapi seperti yang saya katakan - saya tidak melihat aplikasi praktis untuk ini.

Sistem input-output


Untuk berkomunikasi dengan pengguna, antarmuka UART-USB dan WEB digunakan. Saya berpikir tentang UART. Saya tidak perlu berbicara secara rinci. Satu-satunya hal yang patut diperhatikan adalah untuk kenyamanan dan kompatibilitas dengan non-ESP fungsi serialEvent () diimplementasikan:

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

Dengan antarmuka WEB, semuanya jauh lebih menarik. Kami mencurahkan bagian terpisah untuk itu.

Antarmuka WEB


Dalam hal perangkat pintar, menurut saya, antarmuka WEB adalah solusi yang paling ramah pengguna.

Saya menganggap penggunaan layar yang terhubung ke perangkat sebagai praktik yang sudah ketinggalan zaman - tidak mungkin untuk membuat antarmuka yang sederhana, nyaman, dan indah saat menggunakan layar kecil dan serangkaian tombol yang terbatas.

Penggunaan program khusus untuk mengontrol perangkat membebankan pembatasan pada pengguna, menambah kebutuhan untuk mengembangkan dan mendukung program-program ini, dan juga mengharuskan pengembang untuk mengurus pengiriman program-program ini ke perangkat terminal pengguna. Dalam cara yang baik, aplikasi harus dipublikasikan di Google, Apple, toko aplikasi Windows, dan juga tersedia di repositori Linux dalam bentuk paket deb dan rpm - jika tidak, akses ke antarmuka perangkat mungkin sulit untuk sebagian audiens.

Akses ke antarmuka WEB perangkat tersedia dari sistem operasi apa pun - Linux, Windows, Android, MacOS, pada desktop, laptop, tablet, smartphone - hanya untuk memiliki browser. Tentu saja, pengembang antarmuka WEB perlu mempertimbangkan fitur berbagai perangkat, tetapi ini terutama menyangkut ukuran dan resolusi. Akses ke antarmuka WEB dari perangkat pintar di rumah / apartemen / pondok mudah disediakan dari luar melalui Internet - sekarang sulit membayangkan rumah / apartemen di mana ada perangkat pintar dan tidak ada router dan Internet, dan di router akses ini dikonfigurasi dalam beberapa klik (bagi mereka yang benar-benar keluar dari topik, kata kunci akan membantu - "port forwarding" dan "DNS dinamis"). Dalam hal tempat tinggal musim panas, akses dapat diberikan menggunakan router 3G.

Untuk mengimplementasikan antarmuka WEB, diperlukan server WEB. Saya menggunakan perpustakaan me-no-dev / ESPAsyncWebServer. Perpustakaan ini menyediakan fungsionalitas berikut:

  • Pengembalian konten statis, termasuk dengan dukungan kompresi gzip. Direktori virtual didukung, dengan kemampuan untuk menentukan file utama (yang biasanya index.htm) untuk setiap direktori.
  • Menetapkan fungsi panggilan balik ke berbagai URL berdasarkan jenis permintaan (GET, POST, ...)
  • Dukungan untuk soket WEB pada port yang sama (itu penting ketika port forwarding).
  • Otorisasi DASAR. Selain itu, otorisasi ditetapkan secara individual untuk setiap URL. Ini penting karena misalnya, Google Chrome, saat membuat pintasan halaman di layar utama, meminta ikon dan file manifes dan tidak mentransfer data otorisasi. Oleh karena itu, beberapa file ditempatkan di direktori virtual dan otorisasi dinonaktifkan untuk direktori ini.

Sistem operasi layanan HTTP


Dalam proyek saat ini, semua pengaturan sistem operasi dilakukan menggunakan layanan HTTP. Layanan HTTP adalah fungsi pengambilan / modifikasi data independen kecil yang tersedia melalui HTTP. Selanjutnya, pertimbangkan daftar layanan ini.

Bantuan


Implementasi dari daftar perintah, saya pikir itu benar untuk memulai dengan implementasi tim BANTUAN. Di bawah ini adalah blok inisialisasi server 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")); } 

Mengapa saya membutuhkan sistem bantuan, saya pikir itu tidak layak diceritakan. Beberapa pengembang menunda implementasi sistem bantuan untuk nanti, tetapi ini "nanti" biasanya tidak terjadi. Jauh lebih mudah untuk mengimplementasikannya di awal proyek dan menambahnya selama pengembangan proyek.
Dalam proyek saya, daftar layanan yang mungkin juga ditampilkan dengan kesalahan 404 - halaman tidak ditemukan. Saat ini menerapkan layanan berikut:

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 

Seperti yang Anda lihat, dalam daftar layanan tidak ada layanan aplikasi. Semua layanan HTTP terkait dengan sistem operasi. Setiap layanan melakukan satu tugas kecil. Selain itu, jika layanan memerlukan input data apa pun, maka, atas permintaan, GET mengembalikan formulir input minimalis:

 #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 



Kemudian layanan ini digunakan dalam antarmuka yang lebih cantik:



Perangkat lunak aplikasi


Akhirnya kami sampai pada titik di mana sistem itu dibuat. Yaitu - untuk pelaksanaan tugas yang diterapkan.

Aplikasi apa pun harus menerima data sumber, memprosesnya, dan menghasilkan hasilnya. Mungkin juga bahwa sistem harus melaporkan keadaan saat ini.

Sumber data untuk pengontrol pemanas di bawah lantai adalah:

  • Data sensor - sistem tidak terikat dengan sensor tertentu. Identifier unik dihasilkan untuk setiap sensor. Untuk sensor radio, pengenal mereka diisi dengan nol hingga 16 bit, untuk sensor 1Wire, CRC16 dihitung berdasarkan pengenal internal dan digunakan sebagai pengidentifikasi sensor. Dengan demikian, semua sensor memiliki pengidentifikasi dengan panjang 2 byte.
  • Data tentang zona pemanasan - jumlah zona tidak tetap, jumlah maksimum dibatasi oleh modul relai yang digunakan. Dengan batasan ini, antarmuka WEB juga dikembangkan.
  • Suhu dan jadwal target - Saya mencoba membuat pengaturan paling fleksibel, Anda dapat membuat beberapa skema pemanas, dan Anda bahkan dapat menetapkan skema pengaturan Anda sendiri untuk setiap zona.

Dengan demikian, ada sejumlah pengaturan yang perlu diatur entah bagaimana, dan ada sejumlah parameter yang dilaporkan sistem sebagai keadaan saat ini.
Untuk komunikasi antara pengontrol dan dunia luar, saya menerapkan juru bahasa perintah yang memungkinkan saya untuk mengimplementasikan kontrol kedua pengontrol dan menerima data status. Perintah ditransmisikan ke controller dalam bentuk yang dapat dibaca manusia, dan dapat dikirim melalui soket UART atau WEB (jika diinginkan, Anda dapat mengimplementasikan dukungan untuk protokol lain, misalnya telnet).
Baris perintah dimulai dengan karakter '#' dan diakhiri dengan karakter nol atau karakter baris baru. Semua perintah terdiri dari nama perintah dan operan, dipisahkan oleh tanda titik dua. Untuk beberapa perintah, operan bersifat opsional, dalam hal ini, titik dua dan operan tidak ditentukan. Perintah dalam garis dipisahkan oleh koma. Sebagai contoh:

 #ZonesInfo:1,SensorsInfo 

Dan tentu saja, daftar perintah dimulai dengan perintah Bantuan, yang menampilkan daftar semua perintah yang valid (untuk kenyamanan, perintah yang dikirimkan dimulai dengan '>' bukan '#'):

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

Fitur implementasi interpreter perintah adalah bahwa informasi tentang hasil eksekusi perintah juga dikeluarkan dalam bentuk perintah atau seperangkat perintah:

 >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 

Di sisi klien WEB, sebuah shell juga diimplementasikan yang menerima perintah-perintah ini dan mengubahnya menjadi tampilan grafis. Sebagai contoh:

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

Antarmuka WEB mengirim permintaan ke pengontrol tentang zona nomor 3, dan sebagai tanggapan menerima nama zona, pengidentifikasi sensor yang terkait dengan zona, pengidentifikasi sirkuit yang ditugaskan ke zona dan koreksi suhu untuk zona. Shell tidak memahami bilangan pecahan, sehingga suhunya ditransmisikan dalam sepersepuluh derajat, yaitu. 12,3 derajat adalah 123 persepuluh.

Fitur kuncinya adalah pengontrol merespons semua klien sekaligus untuk perintah apa pun, apa pun metode memasukkan perintah. Ini memungkinkan Anda untuk segera menampilkan perubahan status di semua sesi antarmuka WEB. Karena Transportasi pertukaran utama antara pengontrol dan antarmuka WEB adalah soket WEB, kemudian pengontrol dapat mengirimkan data tanpa permintaan, misalnya, ketika data baru berasal dari sensor:

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

Atau, misalnya, bahwa zona ini perlu diperbarui:

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

Antarmuka WEB pengendali didasarkan pada penggunaan perintah teks. Di salah satu tab antarmuka ada terminal tempat Anda dapat memasukkan perintah dalam bentuk teks. Juga, tab ini, untuk keperluan debugging, memungkinkan Anda untuk mengetahui perintah apa yang dikirim dan diterima antarmuka WEB dengan berbagai tindakan pengguna.

Interpreter perintah memudahkan untuk mengubah dan meningkatkan fungsionalitas perangkat dengan mengubah perintah yang ada dan menambahkan yang baru. Pada saat yang sama, debugging dari sistem seperti itu sangat disederhanakan, karena komunikasi dengan pengontrol dilakukan secara eksklusif dalam bahasa yang dapat dibaca manusia.

Kesimpulan


Menggunakan pendekatan serupa, yaitu:

  • Pemisahan perangkat lunak ke dalam sistem operasi dan program aplikasi
  • Menerapkan pengaturan sistem operasi dalam bentuk layanan HTTP minimalis
  • Memisahkan logika sistem dari penyajian data
  • Menggunakan protokol komunikasi yang dapat dibaca manusia

memungkinkan Anda untuk membuat solusi yang dapat dimengerti oleh pengguna dan pengembang. Solusi semacam itu mudah dimodifikasi. Berdasarkan solusi tersebut, mudah untuk membangun perangkat baru dengan logika yang sama sekali berbeda, tetapi akan bekerja dengan prinsip yang sama. Anda dapat membuat garis perangkat dengan jenis antarmuka yang sama:



Seperti yang Anda lihat, dalam proyek ini hanya tiga halaman pertama dari antarmuka yang terkait langsung dengan aplikasi, dan sisanya hampir bersifat universal.

Dalam publikasi ini, saya hanya menjelaskan pendapat saya tentang pembangunan perangkat pintar, dan dalam kasus apa pun saya tidak mengklaim sebagai kebenaran tertinggi.

Kepada siapa topik ini menarik - tulis, mungkin saya salah tentang sesuatu, tetapi mungkin beberapa detail masuk akal untuk dijelaskan secara lebih rinci.

Apa yang terjadi pada akhirnya: Fiasco. Kisah satu IoT buatan sendiri

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


All Articles