HomeKit dan ioBroker Mari berteman di rumah


Tidak diragukan lagi, Apple iOS tetap menjadi salah satu OS seluler paling populer, yang berarti bahwa sistem otomasi modern harus dapat berintegrasi ke dalam ekosistem ini dan menyediakan interoperabilitas. Inilah yang dirancang untuk kerangka Homekit, yang memungkinkan Anda untuk bekerja dengan perangkat pintar dari layar iPhone / iPad / iWatch, dan yang terbaru, Mac (macOS Mojave).


Sebagian besar sistem otomasi (saya tidak suka nama pemasaran "rumah pintar") telah lama menyertakan modul untuk diintegrasikan dengan Homekit, tetapi bahkan pengguna yang terlatih tidak dapat selalu mencari tahu bagaimana membuat perangkat mereka tersedia di aplikasi Rumah (atau Hawa).


Hari ini saya akan memberi tahu Anda cara melakukan manipulasi ini dalam sistem ioBroker (ini adalah sistem otomasi terbuka dan gratis). Tetapi agar tidak secara bodoh memberikan banyak contoh perangkat, saya ingin menjelaskan beberapa prinsip dan menunjukkan pendekatan, mengetahui yang mana, Anda dapat dengan mudah menerapkan contoh lain.


"Mengetahui beberapa prinsip dengan mudah mengimbangi ketidaktahuan tentang beberapa fakta."
Claude Adrian Helvetius


ioBroker. Driver, Perangkat, dan Status


Pertama-tama, saya ingin menjelaskan apa itu perangkat dalam sistem ioBroker, dan bagaimana perangkat itu disajikan.


Biarkan saya mengingatkan Anda bahwa sistem ioBroker adalah modular, dan modul ekstensi disebut driver (atau adaptor). Driver adalah modul integrasi dengan beberapa perangkat atau grup perangkat, disatukan oleh fungsionalitas umum, protokol atau pabrikan, dan karenanya dapat "menyeret" satu atau beberapa perangkat ke dalam sistem ioBroker. Fitur lain adalah kemampuan untuk membuat banyak instance dari driver yang sama, berbeda dalam pengaturan apa pun.


Tetapi setiap perangkat unik dan tak dapat ditiru, memiliki karakteristik dan kemampuan yang berbeda. Berdasarkan ini, ioBroker berfokus terutama bukan pada perangkat itu sendiri, tetapi pada karakteristiknya, yang diwakili oleh negara. Status adalah objek ioBroker internal yang menerima dan menyimpan nilai. Sinonim dari negara dapat dipertimbangkan: tanda, atribut, karakteristik, properti, peristiwa. Contoh kondisi: "suhu", "level kecerahan", "level baterai", "power-on flag", "flag kesalahan", "flag yang menekan", "flag yang menekan dua kali", dll. Dengan demikian, setiap perangkat diwakili oleh banyak negara yang berbeda.


Struktur Objek


Negara dapat dibagi menjadi yang informatif - mereka menampilkan informasi dari perangkat, dan yang bisa berubah - mereka dapat diubah oleh pengguna atau skrip dan mengirimkan perubahan ini ke perangkat. Dengan demikian, ketika sesuatu berubah pada perangkat - data ini ditampilkan di negara-negara, dan ketika negara berubah dari ioBroker (oleh pengguna atau skrip) - perangkat menerima sinyal tentang perubahan dan harus merespons sesuai (itu tergantung pada perangkat itu sendiri dan driver dengan itu. bekerja).


Semua status perangkat digabungkan menjadi satu pohon (registri) status. Mereka dikelompokkan pertama berdasarkan perangkat (dalam beberapa kasus, penyaluran masih digunakan), dan kemudian oleh instans driver.


Konsep topik protokol MQTT dengan mudah masuk ke pohon negara tersebut. Dengan cara ini, Anda dapat menghubungkan peralatan tambahan atau sistem pihak ketiga yang mendukung protokol MQTT. Cukup menginstal driver MQTT - cabang yang sesuai akan muncul di pohon negara.


Dan ada semua jenis layanan online yang dapat memberikan informasi yang berguna dan / atau memungkinkan untuk mengendalikan peralatan lain (misalnya alarm mobil). Hasil interaksi dengan layanan ini juga direpresentasikan sebagai seperangkat negara.


Pohon negara


Secara total, perangkat di ioBroker diwakili oleh serangkaian status yang mencirikan perangkat dan memungkinkan untuk berinteraksi dengannya.


Homekit Aksesori, layanan, dan spesifikasi


Sekarang buka Homekit. Di sini klasifikasi perangkat, fungsi dan karakteristiknya diterapkan.


Kategori Perangkat Homekit


Aksesori setara dengan perangkat fisik. Aksesori memiliki kategori untuk menetapkannya ke grup tertentu.


Layanan setara dengan fungsionalitas yang dimiliki aksesori. Satu aksesori dapat memiliki beberapa layanan.


Layanan menunjukkan kemampuan perangkat: lampu, baterai, tombol, sensor kualitas udara, pintu, pembersih udara, kamera ..


Ini adalah layanan yang menentukan tampilan, perilaku perangkat, dan serangkaian karakteristik.


Karakteristik adalah padanan dari atribut / properti yang menjadi ciri suatu layanan. Ini adalah karakteristik yang menentukan apakah perangkat dihidupkan, tingkat kecerahan lampu, atau berapa kali tombol ditekan. Satu layanan dapat memiliki banyak karakteristik.


Struktur Objek


Aplikasi yang bekerja dengan Homekit membaca layanan dan karakteristik aksesori, lalu menampilkan dan membiarkan Anda mengubah nilai karakteristik melalui antarmuka pengguna. Nilai yang diubah dikirim ke perangkat Homekit untuk menerapkannya, dan dari perangkat Homekit, masing-masing, juga nilai karakteristik dikirim dengan beberapa perubahan dari sisi perangkat.


Secara total, perangkat di HomeKit tampaknya menjadi aksesori dengan serangkaian layanan dan fitur.


Yahka. Kami bergabung dengan konsep


Untuk bekerja dengan Homekit, ioBroker menggunakan driver Yahka (Anda harus menginstal modul tambahan sebelum menginstal) - add-on ke perpustakaan terkenal https://github.com/KhaosT/HAP-NodeJS , yang juga membangun proyek HomeBridge yang populer. Pustaka ini dirancang untuk membuat gateway / jembatan virtual yang menyediakan satu set perangkat virtual di HomeKit. Mengkonfigurasi perangkat virtual dan layanan yang sesuai, mengatur nilai-nilai karakteristik, kita mendapatkan perangkat jadi di Homekit dan aplikasi Home, dan kita juga dapat meminta Siri untuk mengelolanya.


Driver Yahka hanya dirancang untuk mengonfigurasi aksesori, menambahkan layanan kepadanya dan menunjukkan korespondensi karakteristik (HomeKit) dan status (ioBroker).


Tetapi pertama-tama, setelah instalasi, Anda perlu mengkonfigurasi gateway dan memasukkannya ke aplikasi Home. Setelah konfigurasi, semua perangkat yang ditambahkan ke gateway akan secara otomatis ditambahkan ke Home. Untuk melakukan ini, tentukan "Nama Perangkat" (diinginkan untuk menentukan hanya huruf Latin) dan ingat kode pin (atau atur sendiri).


Pengaturan gerbang


Kami pergi ke aplikasi Home dan menambahkan aksesori baru.



Sekarang mari kita turun ke perangkat. Semuanya akan baik-baik saja jika set negara untuk perangkat di ioBroker jelas terkait dengan set layanan dan fitur di HomeKit. Dan akan lebih baik lagi jika nilai-nilai di negara-negara cocok untuk nilai-nilai karakteristik. Tetapi sering kali tidak demikian, dan Anda harus menemukan cara yang tidak biasa untuk berlabuh. Saya akan berbicara tentang beberapa di bawah ini, dan Anda harus menerapkan semua opsi lain sendiri, "dalam gambar dan rupa."


Untuk kenyamanan, saya membuat dokumen dengan terjemahan layanan dan jenis, serta kemungkinan nilai karakteristik. Semua jenis dan layanan yang digunakan sesuai dengan perpustakaan HAP-NodeJS .


Sensor suhu


Ini adalah contoh paling sederhana - yang harus Anda lakukan adalah memiliki satu negara yang berisi nilai numerik suhu. Ini dapat diperoleh dari mana saja: dari sensor atau dari layanan Internet (cuaca).

Anda perlu menambahkan perangkat dari kategori Sensor, dan menambahkan layanan TemperatureSensor ke perangkat, dan memberi nama untuk layanan ini. Ada 5 karakteristik dalam layanan ini, yang terpenting bagi kami adalah CurrentTemperature.


Aksesori termometer


Layanan Sensor Suhu


Cukup untuk menunjukkan nama negara yang sesuai dengan suhu dalam karakteristik CurrentTemperature.


Tambahkan juga layanan kelembaban Sensor Kelembaban di sini, dan ikon aksesori terpisah akan dibuat di Homekit.


Layanan Sensor Kelembaban


Simpan, dan Anda selesai. Sekarang Anda dapat beralih ke Siri, dan bertanya kepadanya tentang suhu dan kelembaban.



Percakapan dengan Siri



Baterai


Layanan sederhana lainnya. Triknya adalah ia dapat ditambahkan ke hampir semua aksesori. Tambahkan layanan BatteryService dan tunjukkan dalam karakteristik BatteryLevel status yang berisi persentase pengisian daya baterai. Setelah itu, data biaya akan muncul di data tambahan tentang perangkat.


Layanan Baterai


Anda dapat segera mengatur tanda “muatan rendah” (karakteristik StatusLowBattery), jika nilai negara yang ditentukan sama dengan 1, ikon yang sesuai akan ditampilkan pada gambar perangkat.


Tetapi bagaimana jika Anda tidak memiliki status seperti itu, tetapi ingin melihat ikon hemat daya? Anda perlu membuat status ini secara manual atau menggunakan skrip, dan menunjukkan status yang dibuat dalam karakteristik.


Sekarang tinggal menetapkan nilai yang benar dengan benar dalam kondisi ini. Untuk melakukan ini, kita akan menggunakan skrip - itu akan menjadi kenyataan ketika baterai mencapai 30 persen.


createState(""); on({id: "zigbee.0.00158d0001f41725.battery", change: "ne"}, function (obj) {   var value = obj.state.val; setState("javascript.0.", (value <= 30)); }); 

Setelah dijalankan pertama kali, skrip akan membuat status, dan itu dapat dipilih dalam karakteristik.



Tanda ini akan ditampilkan pada gambar aksesori



dan detail perangkat


Lampu


Bola lampu berbeda - terang, hangat, merah. Ada 4 kasus:


  • Sederhana - dikendalikan oleh on dan off
  • Dimmable - juga dikendalikan oleh tingkat kecerahan
  • Dengan suhu - dimungkinkan untuk mengontrol suhu cahaya
  • Warna - Anda dapat mengontrol warna cahaya

Untuk masing-masing kasus ini, ada karakteristik terkait dalam layanan Bola Lampu:


  • Nyala / mati
  • Brightness - tingkat kecerahan
  • Hue - teduh
  • Kejenuhan - Kejenuhan
  • ColorTemperature - suhu warna

Dalam kasus sederhana, dalam karakteristik "Aktif", kami menunjukkan status yang bertanggung jawab untuk menghidupkan dan mematikan.



Jika lampu ini dapat diredupkan, maka kami juga menunjukkan status dengan tingkat kecerahan.



Selain menetapkan status yang benar, penting untuk mengamati interval nilai yang dapat diterima!


Contoh: dalam beberapa kasus, negara yang bertanggung jawab atas kecerahan lampu dapat mengambil nilai dari 0 hingga 255, tetapi dalam Homekit nilai-nilai ini terbatas pada interval dari 0 hingga 100. Untuk kasus ini, Anda dapat menggunakan fungsi konversi driver Yahka. Fungsi "level255" hanya mengubah interval nilai 0..255 ke interval 0..100 (dan sebaliknya).


Kesulitan berikut mungkin muncul jika lampu Anda berwarna, tetapi warna yang digunakan adalah RGB. Ini dapat berupa tiga status berbeda, atau satu angka (atau string). Dalam hal ini, Anda perlu mengkonversi dari satu ruang warna RGB ke ruang XYB lain (ruang ini digunakan oleh HomeKit), atau ke bidang XY.


Untuk melakukan ini, Anda perlu membuat 2 status baru (Hue dan Saturation), di mana kami akan mengonversi nilai dari status RGB dan sebaliknya.


Script yang dihasilkan untuk warna adalah
 //       createState("Hue"); createState("Sat"); //      RGB- on({id: "Hue", ack: false, change: 'any'}, function (obj) {  var hue = parseInt(obj.state.val);  var sat = parseInt(getState('Sat').val);  var res = hsvToRgb(hue, sat, 100);  setRGB(parseInt(res[0]), parseInt(res[1]), parseInt(res[2])); }); //    RGB- function setRGB(r, g, b){  var val = ('00'+r.toString(16)).slice(-2)+('00'+g.toString(16)).slice(-2)+('00'+b.toString(16)).slice(-2);  // RGB-   setState('zigbee.0.00124b0014d016ab.color', val, false); } //   HSV   RGB function hsvToRgb(h, s, v) {  var r, g, b;  var i;  var f, p, q, t;   h = Math.max(0, Math.min(360, h));  s = Math.max(0, Math.min(100, s));  v = Math.max(0, Math.min(100, v));  s /= 100;  v /= 100;   if(s == 0) {      r = g = b = v;      return [          Math.round(r * 255),          Math.round(g * 255),          Math.round(b * 255)      ];  }   h /= 60;  i = Math.floor(h);  f = h - i;  p = v * (1 - s);  q = v * (1 - s * f);  t = v * (1 - s * (1 - f));   switch(i) {      case 0:          r = v;          g = t;          b = p;          break;       case 1:          r = q;          g = v;          b = p;          break;       case 2:          r = p;          g = v;          b = t;          break;       case 3:          r = p;          g = q;          b = v;          break;       case 4:          r = t;          g = p;          b = v;          break;       default: // case 5:          r = v;          g = p;          b = q;  }   return [      Math.round(r * 255),      Math.round(g * 255),      Math.round(b * 255)  ]; } 

Temperatur warna dapat dilakukan dengan lebih mudah - jika rentang nilai yang tersedia untuk lampu Anda diketahui, maka dapat dikonversi ke interval yang tersedia untuk HomeKit (melalui fungsi scaleInt ).


Layanan Bola Lampu



Lebih dalam di lampu



Termostat


Thermostat - perangkat untuk mempertahankan suhu yang disetel (layanan Thermostat). Dengan demikian, karakteristik utama dari termostat adalah suhu yang diinginkan (TargetTemperature). Selain suhu yang disetel, suhu saat ini (CurrentTemperature) dapat ditunjukkan, yang bersifat informasi (karena perangkat hanya membacanya dari sensor).


Dari aplikasi Rumah, suhu target diatur dalam termostat dan suhu saat ini dipantau. Di termostat saya (Zont) hanya ada dua negara ini - mereka tersedia melalui layanan cloud api.


Untuk keindahan menampilkan perangkat di HomeKit, saya harus menambahkan beberapa konstanta: kondisi pemanasan saat ini aktif (1), kondisi target pemanasan adalah otomatis (3).


Layanan Termostat



Pemilihan suhu


Gates


Dengan pintu garasi (layanan GarageDoorOpener), semuanya lebih rumit daripada dengan termostat.


Dari karakteristik yang tersedia, gerbang memiliki status target (TargetDoorState), yang menunjukkan keinginan kita untuk gerbang menjadi "terbuka" atau "ditutup". Tetapi Anda juga harus menampilkan dengan benar keadaan gerbang saat ini (CurrentDoorState): apakah mereka membuka atau menutup, atau mungkin mereka membuka atau menutup?


Dalam kasus saya, gerbang dibuka melalui mqtt di ioBroker dengan beberapa status informasi:


  • tanda keterbukaan gerbang (OB)
  • tanda pergerakan gerbang (LW)

Status Kontrol Pintu Garasi


Berkat status ini, Anda dapat menghitung status gerbang saat ini:


  • jika tidak ada OB dan tidak ada DV, maka gerbang ditutup
  • jika tidak ada OB dan ada DV, maka gerbang akan terbuka
  • jika ada OB dan tidak ada DV, maka gerbang terbuka
  • jika ada OB dan ada DV, maka gerbang ditutup

Untuk mengirim sinyal untuk membuka dan menutup gerbang, saya memiliki dua keadaan terpisah (akan mungkin untuk mengelola dengan satu keadaan, tetapi saya memiliki dua keadaan), yang mengirim pesan melalui mqtt ke pengontrol kontrol gerbang:


  • sinyal pembuka
  • sinyal penutupan

Untuk mengirim sinyal, Anda perlu mensimulasikan tombol "klik": atur nilainya menjadi true, dan setelah beberapa saat atur ulang ke false. Dalam hal ini, untuk berintegrasi dengan HomeKit, perlu untuk membuat negara lain - "negara tujuan gerbang", ketika diubah, sinyal yang sesuai akan dikirim.


Tanda keterbukaan gerbang dapat digantikan oleh status target (mis. Tujuan apa yang akan dituju):


  • jika CA "ditutup" dan tidak ada DV, maka gerbang ditutup
  • jika CA "tertutup" dan ada DV, maka gerbang terbuka
  • jika CA "terbuka" dan tidak ada DV, maka gerbang terbuka
  • jika CA "terbuka" dan ada DV, maka gerbang ditutup

Kami juga akan membuat keadaan terpisah "gerbang saat ini", dan kami akan mengisinya dalam skrip tergantung pada nilai tanda dan pada negara target.


Sebutkan naskah perubahan untuk pintu garasi
 createState("gate_0.current"); //   createState("gate_0.target"); //   //    0,   300 on({id: "mqtt.0.gate.gpio.13", ack: false, val: 1}, function (obj) {  setStateDelayed("mqtt.0.gate.gpio.13", 0,  300); }); on({id: "mqtt.0.gate.gpio.12", ack: false, val: 1}, function (obj) {  setStateDelayed("mqtt.0.gate.gpio.12", 0,  300); }); //     on({id: "mqtt.0.gate.is_open", ack: false, val: 1}, function (obj) {  // ""  setState("javascript.0.gate_0.current", 0, true); }); on({id: "mqtt.0.gate.is_open", ack: false, val: 0}, function (obj) {  // ""  setState("javascript.0.gate_0.current", 1, true); }); //    - ,      on({id: "javascript.0.gate_0.target", ack: false, val: 0}, function (obj) {  setState("mqtt.0.gate.gpio.12", 1); }); //    - ,      on({id: "javascript.0.gate_0.target", ack: false, val: 1}, function (obj) {  setState("mqtt.0.gate.gpio.13", 1); }); on({id: "mqtt.0.gate.in_progress", ack: true, change: 'any'}, function (obj) {  //    " ",      if (obj.state.val === 1) {      //    "",         const target = getState("javascript.0.gate_0.target");      if (target.val === 0) {          // ""          setState("javascript.0.gate_0.current", 2, true);      } else {          // ""          setState("javascript.0.gate_0.current", 3, true);      }  }  //    " ",      if (obj.state.val === 0) {      //    "",         const target = getState("javascript.0.gate_0.target");      if (target.val === 0) {          // ""          setState("javascript.0.gate_0.current", 0, true);      } else {          // ""          setState("javascript.0.gate_0.current", 1, true);      }  } }); 

Setelah menjalankan skrip, Anda dapat mengonfigurasi karakteristik layanan pintu garasi:


Layanan GarageDoorOpener



Kamera


Untuk menambahkan kamera ke HomeKit, metode "klasik" akan digunakan. Penyiaran gambar dari kamera melalui modul ffmpeg diatur. Melalui itu, aliran input akan dikodekan, dienkripsi, dan diberikan ke Homekit.


Pertama-tama, Anda perlu menginstal ffmpeg di server tempat ioBroker berada.


Untuk setiap platform, diinstal dengan cara yang berbeda, Anda dapat mengumpulkannya dari sumber, atau mencari perakitan yang sudah jadi, misalnya, di sini: https://www.johnvansickle.com/ffmpeg/ Harus memiliki enkoder libx264. Anda dapat memeriksa pembuat enkode setelah menginstal ffmpeg dengan perintah:


 ffmpeg -codecs | grep 264 

Hasilnya harus berisi garis formulir:


 DEV.LS h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_v4l2m2m h264_vdpau ) (encoders: libx264 libx264rgb h264_v4l2m2m ) 

Untuk Raspberry Pi 3, Anda dapat menggunakan rakitan siap pakai , yang memiliki codec dengan dukungan untuk penyandian perangkat keras GPU (h264_omx, lebih sedikit sumber daya). Letakkan seperti ini:


 wget https://github.com/legotheboss/YouTube-files/raw/master/ffmpeg_3.1.4-1_armhf.deb sudo dpkg -i ffmpeg_3.1.4-1_armhf.deb 

Kedua codec hadir dalam majelis ini: libx264 dan h264_omx


Selanjutnya, Anda perlu mendapatkan alamat aliran kamera yang perlu disiarkan (langkah ini di luar cakupan artikel ini). Misalnya, Anda dapat mengambil aliran publik yang sudah jadi .


Sekarang tambahkan kamera ke Yahka, tunjukkan alamat aliran, dan jika perlu ubah parameter codec, ukuran gambar, kecepatan bingkai.


Penting: kombinasi parameter sangat penting untuk tampilan kamera yang benar di Homekit dan bergantung pada kamera dan streaming. Ini juga mempengaruhi kinerja sistem, seperti Proses berjalan ffmpeg menghabiskan banyak sumber daya.


Menambahkan Kamera


Pengaturan aliran


Kamera ditambahkan sebagai perangkat terpisah di luar gateway, dan mereka harus ditambahkan dengan cara yang sama seperti gateway


Thumbnail kamera


Siaran dari kamera


Bonus


Sebagai bonus, saya akan berbicara tentang penggunaan siaran kamera yang tidak biasa.


Dengan menggunakan ffmpeg yang sama, alih-alih kamera, Anda dapat mencoba menyiarkan gambar, gambar apa pun. Gambar-gambar ini juga dapat dikombinasikan dengan aliran video. Anda dapat menampilkan teks, grafik, dan informasi lain pada gambar.


Cast Overlay Teks


Hasilnya, Anda bisa mendapatkan dasbor yang menarik. Dan jika Anda memperbarui gambar secara berkala, Anda mendapatkan data dinamis.


Sebagai contoh, saya mengeluarkan grafik perubahan dalam beberapa indikator dalam bentuk gambar (file pada disk). Grafik ini diperbarui satu menit sekali dan menimpa gambar dalam file.


(fungsi createImage1, createImage2, pembentukan grafik dan pengenaan teks pada gambar berada di luar ruang lingkup artikel ini, tapi saya akan memberikan petunjuk).

Saya akan memberi tahu Anda bagaimana Anda bisa mendapatkan grafik dalam bentuk gambar.


IoBroker memiliki cara standar untuk membuat grafik - driver Flot. Driver ini dipasangkan dengan driver web dan menampilkan hasilnya di browser. Tetapi untuk mendapatkan grafik yang dibuat di server (dalam skrip) sebagai gambar, diperlukan driver PhantomJS tambahan, yang mengambil "tangkapan layar" halaman (di mana kita akan menggambar grafik Flot).


Tetapi saya akan berbicara tentang cara alternatif untuk membuat grafik di server dalam sebuah skrip.


Ada perpustakaan Chart.js http://www.chartjs.org/ yang memungkinkan Anda menggambar grafik yang tampak bagus di peramban (contoh http://www.chartjs.org/samples/latest/ ).


Untuk menggambar, ia menggunakan "kanvas" (kanvas, kanvas) browser. Oleh karena itu, untuk menggambar menggunakan perpustakaan ini di server, Anda perlu menggunakan versi "server" dari "kanvas" dan objek DOM. Inilah yang dilakukan oleh paket chartjs-node ( https://github.com/vmpowerio/chartjs-node ).


Ketergantungan utama untuk paket ini adalah paket kanvas ( https://github.com/Automattic/node-canvas ), yang harus diinstal secara global (atau dalam folder iobroker). Penting untuk menginstal semua dependensi untuk platform tempat Anda meletakkan https://github.com/Automattic/node-canvas#compiling .


Setelah itu, Anda dapat menambahkan modul chart.js, chartjs-node dalam pengaturan driver javascript. Mereka harus menginstal dengan benar, tanpa kesalahan. Jika tidak, atasi kesalahan dan selesaikan.


Dan kemudian, Anda dapat menulis skrip.


Di bawah ini adalah skrip untuk contoh, sebagai itu termasuk penggunaan driver Sejarah dan menggunakan nama negara tertentu.


Perhatian! Script memiliki konstruksi yang rumit untuk pemula - Janji. Ini adalah cara yang mudah untuk tidak menulis fungsi dengan callback, tetapi untuk membuat rantai langkah. Jadi, misalnya, mudah untuk melakukan ini untuk mendapatkan data dari sejarah negara.


 'use strict'; const ChartjsNode = require('chartjs-node'); /** *  sendTo  Promise,      */ function sendToPromise(adapter, cmd, params) { return new Promise((resolve, reject) => { sendTo(adapter, cmd, params, (result) => { resolve(result); }); }); } //    const chartColors = { black: 'rgb(0, 0, 0)', red: 'rgb(255, 99, 132)', orange: 'rgb(255, 159, 64)', yellow: 'rgb(255, 205, 86)', green: 'rgb(75, 192, 192)', blue: 'rgb(54, 162, 235)', purple: 'rgb(153, 102, 255)', grey: 'rgb(201, 203, 207)' }; /** *        * : * @param config -     * @param filename -     * : * @param Promise -    */ function doDraw(config, filename) { //     640x480  var chartNode = new ChartjsNode(640, 480); return chartNode.drawChart(config) .then(() => { //     return chartNode.writeImageToFile('image/png', filename); }); } /** *     ChartJS. * : * @param Promise -    */ function prepareDraw0(){ // ,    var ; //  Promise     return new Promise((resolve, reject)=>{resolve()}) //       ,      .then(()=>{ //  ,   ,      = [ {"val":3,"ack":1,"ts":1539063874301}, {"val":5,"ack":1,"ts":1539063884299}, {"val":5.3,"ack":1,"ts":1539063894299}, {"val":3.39,"ack":1,"ts":1539063904301}, {"val":5.6,"ack":1,"ts":1539063914300}, {"val":-1.3,"ack":1,"ts":1539063924300}, {"val":-6.3,"ack":1,"ts":1539063934302}, {"val":1.23,"ack":1,"ts":1539063944301}, ]; }) //   -    .then(()=>{ const chartJsOptions = { //   -  type: 'line', data: { //    datasets: [ { //   label: '', //  backgroundColor: chartColors.black, borderColor: chartColors.black, //   pointRadius: 3, //    borderWidth: 3, //     ''        data: .map((item) => { return {y: item.val, t: new Date(item.ts)} }), //   -  fill: false, } ] }, options: { //   legend: { labels: { //   fontSize: 20, }, }, //   scales: { //  X xAxes: [{ //  -   type: 'time', display: true, //   scaleLabel: { display: true, labelString: '' }, }], //  Y yAxes: [{ //  -  type: 'linear', display: true, //   scaleLabel: { display: true, labelString: '' }, }] } } }; return chartJsOptions; }); } /** *     ChartJS. *         , *     . * * : * @param hours -  ,     * : * @param Promise -    */ function prepareDraw1(hours){ //   ,      const end = new Date().getTime(), start = end - 3600000*(hours || 1); // 1 =   //  ,       //   var , 2, 1, 2, 2; //  Promise     return new Promise((resolve, reject)=>{resolve()}) //       'mqtt.0.ESP_Easy..Temperature' .then(() => { return sendToPromise('history.0', 'getHistory', { id: 'mqtt.0.ESP_Easy..Temperature', options: { start: start, end: end, aggregate: 'onchange' } } ).then((result) => { //     ''  = result.result; }); }) //       'sonoff.0.chicken2.DS18B20_Temperature' .then(() => { return sendToPromise('history.0', 'getHistory', { id: 'sonoff.0.chicken2.DS18B20_Temperature', options: { start: start, end: end, aggregate: 'onchange' } }).then((result)=>{ //     '2' 2 = result.result; }); }) .then(() => { return sendToPromise('history.0', 'getHistory', { id: 'sonoff.0.sonoff_chicken_vent.DS18B20_Temperature', options: { start: start, end: end, aggregate: 'onchange' } }).then((result)=>{ 1 = result.result; }); }) .then(() => { return sendToPromise('history.0', 'getHistory', { id: 'sonoff.0.chicken2.POWER1', options: { start: start, end: end, aggregate: 'onchange' } }).then((result)=>{ 2 = result.result; }); }) .then(() => { return sendToPromise('history.0', 'getHistory', { id: 'sonoff.0.chicken2.POWER2', options: { start: start, end: end, aggregate: 'onchange' } }).then((result)=>{ 2 = result.result; }); }) //   -    .then(()=>{ const chartJsOptions = { //   -  type: 'line', data: { //    datasets: [ { //           label: ' ('+[.length - 1].val+')', //  backgroundColor: chartColors.blue, borderColor: chartColors.blue, //  . 0 -   pointRadius: 0, //    borderWidth: 3, //     ''        data: .map((item) => { return {y: item.val, t: new Date(item.ts)} }), //   -  fill: false, //   Y yAxisID: 'y-axis-1', },{ label: ' 1 ('+1[1.length - 1].val+')', backgroundColor: chartColors.green, borderColor: chartColors.green, pointRadius: 0, borderWidth: 3, data: 1.map((item) => { return {y: item.val, t: new Date(item.ts)} }), fill: false, yAxisID: 'y-axis-1', },{ label: ' 2 ('+2[2.length - 1].val+')', backgroundColor: chartColors.red, borderColor: chartColors.red, pointRadius: 0, borderWidth: 3, data: 2.map((item) => { return {y: item.val, t: new Date(item.ts)} }), fill: false, yAxisID: 'y-axis-1', },{ label: ' 2  ('+2[2.length - 1].val+')', backgroundColor: chartColors.yellow, borderColor: chartColors.yellow, pointRadius: 0, borderWidth: 1, data: 2.map((item) => { return {y: (item.val) ? 1 : 0, t: new Date(item.ts)} }), fill: true, lineTension: 0, steppedLine: true, yAxisID: 'y-axis-2', },{ label: ' 2  ('+2[2.length - 1].val+')', backgroundColor: chartColors.grey, borderColor: chartColors.grey, pointRadius: 0, borderWidth: 1, data: 2.map((item) => { return {y: (item.val) ? -1 : 0, t: new Date(item.ts)} }), fill: true, lineTension: 0, steppedLine: true, yAxisID: 'y-axis-2', } ] }, options: { //   legend: { labels: { //   fontSize: 20, }, }, //   scales: { //  X xAxes: [{ //  -   type: 'time', display: true, //   scaleLabel: { display: true, labelString: '' }, //    () time: { unit: 'minute', displayFormats: { minute: 'HH:mm' } }, }], //  Y yAxes: [{ //  -  type: 'linear', display: true, //   scaleLabel: { display: true, labelString: '' }, //   -  position: 'left', //   id: 'y-axis-1', },{ type: 'linear', display: true, scaleLabel: { display: true, labelString: '  ' }, ticks: { min: -4, max: 2 }, //   -  position: 'right', id: 'y-axis-2', }] } } }; return chartJsOptions; }); } function createImage(filename, callback){ // filename -  ,       //    prepareDraw1(2) //     .then((result) => { //        return doDraw(result, filename); }) .then(()=>{ if (callback) callback(); }) .catch((err)=>{ console.error(err); }); } 

Siarkan gambar alih-alih streaming


Gambar kecil diperbarui kira-kira satu kali per menit, jadi kami menetapkan gambar untuk diperbarui setiap 10 detik:


 var fs = require('fs'); //  10    schedule("*/10 * * * * *", () => {  createImage1('/tmp/1_new.jpg', ()=> {      fs.renameSync('/tmp/1_new.jpg', '/tmp/1.jpg');  });  createImage2('/tmp/2_new.jpg', ()=> {      fs.renameSync('/tmp/2_new.jpg', '/tmp/2.jpg');  }); }); 

Keunikannya adalah bahwa dalam proses penyiaran gambar, perlu untuk mengganti gambar dengan cukup cepat sehingga ffmpeg tidak crash :) Oleh karena itu, gambar dibentuk pertama menjadi satu file, dan kemudian file tersebut diubah namanya menjadi yang digunakan untuk terjemahan.


Sekarang, dalam pengaturan kamera, tentukan nama file yang dihasilkan alih-alih alamat streaming, dan tambahkan pengaturan bahwa gambar itu "diperbarui" (parameter "-loop 1"). Ini dikonfigurasikan dalam properti kamera tingkat lanjut. Properti ini tidak lebih dari opsi baris perintah untuk menjalankan ffmpeg. Oleh karena itu, kombinasi parameter harus ditemukan dalam dokumentasi dan contoh ffmpeg.


Properti dibagi menjadi 2 jenis: untuk mendapatkan "pratinjau" (gambar kamera kecil) dan untuk penyiaran. Oleh karena itu, Anda dapat menentukan file sumber gambar yang berbeda, misalnya dengan detail berbeda.


Opsi mulai ffmpeg


Gambar Siaran Langsung


Kesimpulan


ioBroker . , . , , .


, Yahka , Material. , HomeKit.


Yahka, HomeKit — Ham, HomeBridge . .

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


All Articles