bobaos.pub - KNX TP / UART, Raspberry Pi dan Redis


Tidak ada batasan untuk kesempurnaan. Tampaknya semuanya bekerja dengan baik, bug kecil dan sebagainya diperbaiki.


Sekarang saya akan memberi tahu Anda, pertama, tentang masalah yang saya temui selama ini yang telah berlalu sejak artikel sebelumnya, dan, kedua, tentang solusi yang berkontribusi pada status proyek saat ini.


Artikel tentang versi sebelumnya


Penunjukan


modul bobaos - npm untuk berinteraksi dengan BAOS 83x menggunakan UART. Mengembalikan data mentah. Digunakan di semua modul lain yang tercantum di bawah ini.


bdsd.sock - skrip untuk bekerja dengan objek KNX. Menyimpan daftar titik data, mengonversi nilai saat mengirim / menerima. Dari DPT1 ke true / false, dari DPT9 hingga float. Juga mendengarkan Unix Socket untuk menerima permintaan dari proses lain.


bobaos.pub adalah versi baru menggunakan redis untuk komunikasi antarproses.
KNX / - objek komunikasi dari modul BAOS 83x yang dikonfigurasi dalam ETS yang alamat grupnya (a) sesuai (atau tidak). Dalam versi besi saat ini, jumlah maksimum adalah 1000.


Tantangan


Tugas utamanya sama dengan versi sebelumnya. Hanya ada satu koneksi ke port serial. Ada banyak skrip yang bekerja dengan KNX. Selain itu, saya ingin mengimplementasikan komunikasi antarproses. Yaitu sehingga tidak hanya satu proses bdsd.sock soket, tetapi setiap skrip yang berjalan dapat mengirim dan menerima permintaan.


Ide


Sebuah ide muncul di kepala saya untuk membuat broker pesan saya sendiri di node.js di atas soket Unix, tempat klien akan terhubung, berlangganan topik dan menerima / mengirim pesan sesuai dengan kode yang tertulis di dalamnya. Saya tahu bahwa sudah ada solusi yang sudah jadi, yang baru dipelajari oleh orang malas, tetapi gagasan untuk membuat keputusan sendiri adalah obsesif.


Dan sebagai hasilnya, layanan diluncurkan.


Menulis logger yang mengirim pesan ke topik. Pelanggan menerima dan bebas melakukan apa pun, atau lebih tepatnya, apa yang ditentukan. Nyaman - log dari beberapa sumber dapat dilihat dalam satu output konsol.


Saya menulis dan menerbitkan paket bobaos.pub dalam npm, yang, tidak seperti bdsd.sock, tidak lagi membuat file socket, tetapi terhubung ke broker. Sepintas, semuanya berjalan sebagaimana mestinya.


Masalah


Kemudian saya menjalankan skrip yang secara berkala mengirimkan permintaan ke bus KNX dalam semalam. Bangun di pagi hari, dengan lampu LED yang menandakan pengiriman / pengiriman data, saya menyadari bahwa ada sesuatu yang salah. Pesan tidak sampai tepat waktu. Saya menemukan bahwa broker pesan yang ditulis sendiri mengambil hampir semua RAM 512MB yang tersedia (dari BeagleBoard Black). Pekerjaan lebih lanjut dengan nodejs menegaskan bahwa memori adalah titik lemah dari skrip js.


Solusi


Akibatnya, diputuskan untuk beralih dari soket Unix generik ke Redis (ngomong-ngomong, ia juga tahu cara bekerja dengan mereka). Mungkin ada baiknya memilah ingatan, menemukan kebocoran, tetapi saya ingin berlari lebih cepat.


bobaos berarti komunikasi UART dengan pembungkus pesan di FT1.2, kami memiliki komunikasi yang sinkron. Yaitu <..--..> . Modul bobaos, yang bertanggung jawab untuk komunikasi, menyimpan semua permintaan dalam array, menariknya secara bergantian, mengirimkannya ke UART, dan dengan respons yang masuk, memungkinkan janji yang bertanggung jawab atas permintaan ini.


Anda bisa begini: layanan mendengarkan saluran redis PUB / SUB, menerima permintaan, mengirimkannya ke KNX. Dalam hal ini, beban pada antrian permintaan berada pada modul js bobaos . Untuk implementasi, Anda perlu menulis modul sederhana yang berlangganan saluran dan mengonversi pesan menggunakan metode JSON.parse() . Selanjutnya modul ini dapat digunakan dalam skrip lain.


Opsi lain yang akhirnya saya redis : gunakan task manager yang ada di atas redis . Ada beberapa pilihan bee-queue .


Di bawah tenda


Ini menjelaskan cara kerja bee-queue . Jika Anda menerapkan pustaka ini untuk bahasa pemrograman lain, Anda bisa membuat pustaka klien untuk bobaos dengan cara ini.


Dalam versi kedua, semua permintaan disimpan dalam daftar redis , ditarik secara bergantian dan dikirim ke port serial.


Selanjutnya, penulisan ulang versi sebelumnya mengikuti, tapi saya sudah menyimpan semua data pada titik data dalam database redis . Satu-satunya ketidaknyamanan yang saya alami adalah bahwa semua permintaan tidak sinkron, sehingga mendapatkan array nilai sedikit lebih sulit daripada hanya mengakses array.


Optimalisasi kecil telah dilakukan.


Jika sebelumnya ada metode terpisah getValue/getValues/readValue/readValues/setValue/setValues , sekarang getValue/readValue/setValues menerima baik nilai tunggal maupun array.


Metode getValue([id1, id2, ...]) di versi sebelumnya mengirim permintaan ke port serial untuk setiap titik data. Tetapi ada peluang untuk mengirim permintaan untuk beberapa nilai. Keterbatasan - ukuran respons harus sama dengan BufferSize , maksimum - 250 byte; juga tidak mungkin melampaui jumlah objek, untuk versi modul BAOS 83x saat ini - 1000.


Panjang nilai diketahui, header juga. Selanjutnya, algoritma yang cukup sederhana dengan siklus sementara dan menunggu =)


  1. Urutkan array, hapus elemen duplikat, jika ada. kami mendapatkan array idUniq .
  2. Kita memulai siklus i < idUniq.length , di mana kita melakukan hal berikut:
    a) start: idUniq[i] , untuk itu kami mempertimbangkan jumlah nilai maksimum yang bisa kami dapatkan. Misalnya, jika semua objek bertipe DPT1 / DPT5 (1 byte), maka kita bisa mendapatkan nilai dalam jumlah 48. Ada satu komentar: jika, misalnya, kita telah mengkonfigurasi objek #[1, 2, 3, 10, 20] , maka ketika GetDatapointValue.Req(1, 30) , respons akan mengembalikan nol nilai byte tunggal bahkan untuk titik data yang tidak ada [4, 5, 6, ..., 30] .
    b) Penghitungan terjadi dalam siklus baru j < i + max (di mana max adalah 50, atau, jika mendekati 1000, maka maksimum 1000 - id + 1 , untuk 990 akan menjadi 11, untuk 999 - 2), jika dalam proses penghitungan kita bertemu elemen array dari kueri asli, lalu tetapkan indeks i variabel i .
    c) Jika dalam siklus j panjang yang dihitung melebihi panjang buffer maksimum, maka kami membentuk elemen kartu permintaan {start: start, number: number} , jatuhkan ke array yang terpisah, tambah variabel i (atau tetapkan indeks ke idUniq ditemukan dalam array), interupsi siklus j , kedua siklus dimulai ulang.

Jadi, kami membentuk beberapa permintaan untuk bobaos . Misalnya, jika Anda mengirim permintaan getValue([1, 2, 3, 40, 48, 49, 50, 100, 998, 999, 1000]) , maka permintaan dapat berupa sebagai berikut untuk kasus khusus:


 {start: 1, number: 48}, // 1, 2, 3, 40, 48 {start: 49, number: 48}, // 49, 50 {start: 100, number: 48}, // 100 {start: 998, number: 3} // 998, 999, 1000 

Itu bisa dilakukan secara berbeda:


 {start: 1, number: 48}, // 1, 2, 3, 40, 48 {start: 49, number: 2}, // 49, 50 {start: 100, number: 1}, // 100 {start: 998, number: 3} // 998, 999, 1000 

Akan ada banyak permintaan, lebih sedikit data. Tapi saya berhenti di opsi pertama, karena nilai yang diperoleh disimpan dalam database redis , masing-masing, mereka dapat diperoleh dengan menggunakan metode getStoredValue , yang saya coba gunakan lebih sering daripada getValue , yang mengirimkan data melalui port serial.


Antrian terpisah dibuat untuk kondisi ping/get sdk state/reset layanan. Jadi, jika ada sesuatu yang salah dengan komunikasi pada port serial (penghitung frame tersesat, dll.) Dan eksekusi berhenti pada beberapa tugas, Anda dapat mengirim permintaan reset di antrian lain dan, karenanya, restart sdk .


Sisi klien - bobaos.sub


Untuk mengontrol titik data KNX dalam skrip pengguna, modul bobaos.sub dapat digunakan.


Contoh berikut mencakup semua fungsi modul:


 const BobaosSub = require("bobaos.sub"); //     : // redis:   url // request_channel: "bobaos_req"  , // service_channel: "bobaos_service"  , // broadcast_channel: "bobaos_bcast"   let my = BobaosSub(); my.on("connect", _ => { console.log("connected to ipc, still not subscribed to channels"); }); my.on("ready", async _ => { try { console.log("hello, friend"); console.log("ping:", await my.ping()); console.log("get sdk state:", await my.getSdkState()); console.log("get value:", await my.getValue([1, 107, 106])); console.log("get stored value:", await my.getValue([1, 107, 106])); console.log("get server item:", await my.getServerItem([1, 2, 3])); console.log("set value:", await my.setValue({id: 103, value: 0})); console.log("read value:", await my.readValue([1, 103, 104, 105])); console.log("get programming mode:", await my.getProgrammingMode()); console.log("set programming mode:", await my.setProgrammingMode(true)); console.log("get parameter byte", await my.getParameterByte([1, 2, 3, 4])); console.log("reset", await my.reset()); } catch(e) { console.log("err", e.message); } }); my.on("datapoint value", payload => { //   ,  payload    ,    //     Array.isArray(payload) console.log("broadcasted datapoint value: ", payload); }); my.on("server item", payload => { //   ,  payload    ,    //     Array.isArray(payload) console.log("broadcasted server item: ", payload); }); my.on("sdk state", payload => { console.log("broadcasted sdk state: ", payload); }); 

bobaos.tool


Antarmuka baris perintah telah ditulis ulang. Tentang bagaimana saya menerapkannya, artikel berikut:


Menulis CLI di NodeJS


Tim menjadi lebih pendek, lebih jelas dan lebih fungsional.


 bobaos> progmode ? BAOS module in programming mode: false bobaos> progmode 1 BAOS module in programming mode: true bobaos> progmode false BAOS module in programming mode: false bobaos> description 1 2 3 #1: length = 2, dpt = dpt9, prio: low, flags: [C-WTU] #2: length = 1, dpt = dpt1, prio: low, flags: [C-WT-] #3: length = 1, dpt = dpt1, prio: low, flags: [C-WT-] bobaos> set 2: 0 20:27:06:239, id: 2, value: false, raw: [AA==] bobaos> set [2: 0, 3: false] 20:28:48:586, id: 2, value: false, raw: [AA==] 20:28:48:592, id: 3, value: false, raw: [AA==] 

Kata penutup


Hasilnya adalah sistem kerja yang stabil. Redis sebagai backend bekerja dengan baik. Selama pengembangan, banyak kerucut yang dikemas. Tetapi proses belajarnya sedemikian rupa sehingga terkadang hal itu tidak terhindarkan. Dari pengalaman saya, saya perhatikan bahwa proses nodejs mengkonsumsi cukup banyak RAM (20 MB di awal) dan mungkin ada kebocoran. Untuk otomatisasi rumah, ini sangat penting - karena skrip harus bekerja terus-menerus, dan jika skrip ini tumbuh semakin banyak seiring waktu, maka pada titik tertentu ia dapat mengambil semua ruang. Karena itu, Anda harus hati-hati menulis skrip, memahami cara kerja pengumpul sampah, dan menjaga semuanya tetap terkendali.


Memperbarui dokumentasi dapat ditemukan di sini .


Pada artikel selanjutnya saya akan berbicara tentang bagaimana menggunakan redis dan bee-queue membuat layanan untuk aksesori perangkat lunak.


UPD: bobaoskit - aksesoris, dnssd dan WebSocket


Saya akan senang dengan umpan balik apa pun.

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


All Articles