Implementasi sistem otomasi rumah saya

Untuk waktu yang lama saya membaca artikel tentang Habré tentang sistem otomasi rumah, saya ingin menggambarkan apa yang telah saya kerjakan selama lebih dari 2 tahun. Untuk pemahaman yang lebih baik tentang situasi saya, sebuah pengantar kecil diperlukan.

Tiga tahun yang lalu, saya dan keluarga saya pindah ke apartemen tiga kamar baru (67,5 sq.m), meskipun secara teknis apartemen itu sudah tua - Stalin, sebuah rumah yang dibangun pada tahun 1946. Kabel dua kawat aluminium dengan potongan-potongan kabel untai tembaga 1 meter persegi di beberapa tempat. Perombakan ada di depan, saya memutuskan untuk melakukan semuanya sendiri, dan mulai dengan penggantian kabel yang lengkap. Mereka membeli 700 m kabel daya untuk penerangan dan soket 1,5 dan 2,5 sq. Mm, twisted pair bay, sedikit membujuk untuk antena televisi (untuk berjaga-jaga). Mengapa begitu banyak dan apa yang terjadi - saya minta kucing.

Saya memutuskan untuk membuat kabel segera, yaitu: tanpa kotak distribusi, dari setiap titik kabel masuk ke perisai (dengan pengecualian outlet, yang bisa dalam kelompok 2-3 poin, kabel masuk ke perisai dari yang ekstrem, sisanya terhubung oleh satu lingkaran) - t. e. dari masing-masing beralih kabel sendiri ke perisai, dari setiap titik pencahayaan kabelnya sendiri ke perisai, dekat soket sepanjang sepasang titik rj-45, untuk berjaga-jaga. Tentu saja, ada banyak kabel. Di suatu tempat itu diletakkan di lantai sesuai dengan semua aturan PUE, seperti, misalnya, di kamar bayi:



Di suatu tempat - di langit-langit, misalnya, pemandangan pintu kamar:



Sebagai hasilnya, kami mendapatkan semua kabel di koridor di satu tempat di mana perisai akan ditemukan, dan mereka dapat beralih di antara mereka sendiri sesuka Anda. Bahkan jika Anda harus mengubah skema koneksi di masa depan, itu tidak akan memakan banyak waktu dan Anda tidak perlu merusak perbaikan. Dan tentu saja, banyak soket dibuat untuk semua kesempatan - total sekitar 90 poin untuk seluruh apartemen.

Inilah yang tampak seperti "perisai" sementara selama percobaan:



Pemandangan yang mengerikan, tetapi semuanya bekerja dan dalam bentuk ini monster ini hidup selama beberapa bulan. Suatu hari, bintang-bintang berhasil dibentuk dan perisai itu dibangun kembali oleh keputusan yang disengaja. Butuh 3 hari di tangga reyot di bawah langit-langit (dan langit-langit di stalin 3m), tapi itu sepadan. Beginilah tampilan dasbor setelah itu:



Dan tampilan umum:



Ini jauh dari bentuk akhir dari perisai, masih belum cukup RCD, ada pemutus sirkuit 3 kali lebih sedikit dari yang diperlukan, tidak ada relay pulsa - tetapi ada jalur non-putuskan, semua kabel terhubung ke terminal, setidaknya ada semacam selektivitas pemutus sirkuit.

Sekarang setelah Anda memiliki gambaran kasar tentang apa yang harus saya kerjakan, Anda dapat mulai menggambarkan "otak" sistem. Tanpa basa-basi lagi, saya menggunakan arduino sebagai dasarnya, terutama karena saya sudah memiliki 2 papan freeduino, 2 perisai ethernet, dan satu perisai motor yang saya beli jauh sebelum itu. Juga dipesan dari Cina beberapa modul relay masing-masing 4 buah. Dan saya juga menemukan, atas saran salah satu artikel tentang Habré di Ob, sakelar di mana pegas khusus dapat dimasukkan dan sakelar berubah menjadi sakelar tanpa diperbaiki. Saatnya menulis kode.

Secara umum, saya terhubung erat dengan komputer dalam kehidupan. Dia menyelesaikan alas bulu, di mana dia tidak menulis - pascal, c #, c ++, 1c, php, javascript - Anda masih bisa daftar banyak. Terakhir kali saya bekerja di bidang pengembangan web, saya juga berurusan dengan ip-telephony. Oleh karena itu, untuk menghasilkan algoritma itu sederhana, tetapi dengan elektronik “untuk Anda”, saya tahu dan tahu hal-hal sederhana, dan ketika menyangkut sesuatu yang lebih rumit - mikrokontroler, sekering, pantulan kontak - itu lebih sulit. Tapi bukan para dewa yang membakar pot, mata takut, tetapi tangan yang melakukannya. Saya memutuskan untuk membuat semuanya sederhana. Saya memberi makan bumi dari arduino ke input switch, saya menghubungkan output dari switch ke pin analog pada arduino (walaupun dimungkinkan untuk digital, itu tidak penting). Saya menghubungkan pin arduino dengan pin pada modul relay. Secara teknis, semuanya sudah siap, ketika Anda menekan sakelar, Arduino melihat nilai RENDAH pada pin yang diinginkan dan menetapkan RENDAH pada pin yang terhubung ke modul relai.Mengingat bahwa semua kabel dari titik-titik di apartemen datang ke terminal - koneksi tidak memakan banyak waktu.
Untuk memerangi pantulan kontak, setelah mempelajari topik di Internet, perpustakaan Bounce2 dipilih. Secara umum, saya awalnya ingin menulis kode universal sehingga dapat digunakan dengan setidaknya 2 switch, setidaknya 22. Tugas inilah yang menjadi dasar dari keseluruhan algoritma. Nah, sekarang dari kata ke kode. Saya tidak akan sepenuhnya mengunggah semua kode; tautan ke github akan berada di akhir artikel. Dari sudut pandang saya, saya hanya akan menunjukkan momen-momen penting.

Jadi, mendeklarasikan perpustakaan dan variabel:

#include <Bounce2.h>
#include <EEPROM.h>

const byte cnt = 8;
const byte pin_cnt = 19;

int pins[] = {11,12,13,13,14,15,16,17};
int leds[] = {6, 3, 4, 5, 3, 4, 5, 3};

byte init_leds[cnt] ;
byte init_buttons[cnt];
int button_states[cnt];
Bounce debouncers[cnt];
unsigned long buttonPressTimeStamps[cnt];
boolean changed[cnt];

Intinya adalah: itu cukup untuk meningkatkan konstanta dengan jumlah lampu / sakelar dan mendaftarkan asosiasi baru di dalam susunan - dan itu saja, lampu atau sakelar baru akan ditambahkan. Pada saat yang sama, struktur kode memungkinkan satu sakelar untuk mengontrol beberapa perlengkapan sekaligus. Atau beberapa sakelar untuk segera mengontrol satu lampu. Juga, untuk setiap sakelar, turunannya sendiri dari objek Bouncing dibuat untuk anti-bouncing.

Semua array diinisialisasi dalam fungsi pengaturan, dan kami menyimpan status luminer dalam memori non-volatil, sehingga ketika terjadi kegagalan daya atau reboot, semuanya menyala sama seperti yang terjadi sebelum kegagalan.

  for(byte i=0; i<cnt; i=i+1) {
    EEPROM.write(pins[i], 10);
  }

  for(byte i=0; i<cnt; i=i+1) {
    button_states[i] = 0;
    
    byte value = EEPROM.read(leds[i]);
    if(value==11) {
      init_leds[i] = LOW ;
    }else{
      init_leds[i] = HIGH ;
    }
    init_buttons[i] = HIGH;
    buttonPressTimeStamps[i] = 0;
    changed[i] = false;

    debouncers[i] = Bounce();

    pinMode(pins[i], INPUT);
    pinMode(leds[i], OUTPUT);
    
    digitalWrite(pins[i], init_buttons[i]);
    digitalWrite(leds[i], init_leds[i]);
    
    debouncers[i].attach( pins[i] );
    debouncers[i].interval(5);
  }

Saya tidak akan mengatakan apa-apa tentang siklus pertama, kami akan kembali sedikit nanti. Dan yang paling menarik dimulai di tubuh siklus utama.

void loop(){
  for(byte i=0; i<cnt; i=i+1){
    byte dvalue = EEPROM.read(pins[i]);
    if(dvalue!=11) {
      changed[i] = debouncers[i].update();
      
      if ( changed[i] ) {
        int value = debouncers[i].read();
        if ( value == HIGH) {
         button_states[i] = 0;   
        } else {
           if (i > 0 and pins[i] == pins[i-1]) {
             byte prev_value = EEPROM.read(leds[i-1]);
                            
             if(prev_value == 11) {
               digitalWrite(leds[i], LOW );
               EEPROM.write(leds[i], 11);
             }else{
               digitalWrite(leds[i], HIGH);
               EEPROM.write(leds[i], 10);
             }
           } else {               
             byte value = EEPROM.read(leds[i]);
             if(value==11) {
               digitalWrite(leds[i], HIGH );
               EEPROM.write(leds[i], 10);
             }else{
               digitalWrite(leds[i], LOW);
               EEPROM.write(leds[i], 11);
             }
           }
                 
           button_states[i] = 1;
           buttonPressTimeStamps[i] = millis();     
        }
      }
   
      if ( button_states[i] == 1 ) {
        if ( millis() - buttonPressTimeStamps[i] >= 200 ) {
            button_states[i] = 2;
        }
      }
    }
  }

  delay( 10 );
} 

Selama pengujian versi pertama algoritma, tercatat bahwa anak-anak (dan saya memiliki tiga dari mereka, anak laki-laki) sangat suka mengklik sakelar. Oleh karena itu, perlu mematikan beberapa sakelar agar pengontrol tidak meresponsnya. Opsi yang paling jelas adalah dengan hanya melepas pin yang diperlukan dari papan, tetapi ini salah dan tidak menarik. Oleh karena itu, flag juga ditulis ke memori non-volatile yang mengindikasikan apakah sakelar terbuka atau tidak. Ini diinisialisasi dengan loop ini:

  for(byte i=0; i<cnt; i=i+1) {
    EEPROM.write(pins[i], 10);
  }

  ...

Dan diperiksa di sini:

  for(byte i=0; i<cnt; i=i+1){
    byte dvalue = EEPROM.read(pins[i]);
    if(dvalue!=11) {
    ...

Sudah pada tahap ini, sakelar lokal di dinding mulai bekerja. Tapi rumah pintar tidak akan menjadi pintar tanpa antarmuka. Karena saya berurusan dengan pengembangan web, diputuskan untuk membuat antarmuka web. Di sinilah pelindung ethernet berguna. Sayangnya, saya tidak dapat menemukan sumber dari versi pertama program yang menggunakan perisai ethernet untuk kendali jarak jauh. Saya akan mencoba mencari di backup, mungkin ada di sana. Tapi maknanya primitif untuk memalukan. Setiap pengontrol memiliki alamat IP sendiri. Server web naik pada Arduino, yang menganalisis permintaan GET dan menyalakan atau mematikan lampu yang sesuai tergantung pada nomor port. Ada banyak contoh semacam ini di Internet. Untuk antarmuka web, server dibangun pada motherboard dengan Intel Atom bawaan, Ubuntu Server 14.02 diinstal, set LAMP standar dipasang,antarmuka yang sederhana ditulis di sana. Semua sumber juga akan ada di akhir artikel. Saat ini, tampilannya seperti ini:



Seperti yang Anda lihat, satu lampu di dapur dihidupkan, dan sakelar yang bertanggung jawab untuknya terkunci. Manajemennya sangat sederhana - cukup klik pada item yang diinginkan dan perubahan statusnya.

Dan semuanya akan menjadi besar, jika bukan untuk satu "tetapi". Perisai Ethernet terus digantung. Tidak, kontrol lokal dari sakelar selalu bekerja seperti jam. Tetapi remote control dari antarmuka web terus jatuh. Jika manajemen bekerja selama sehari, itu sangat baik. Tetapi lebih sering, perisai digantung hanya beberapa jam setelah reboot. Apa yang saya tidak lakukan adalah mencoba berurusan dengan anjing penjaga, tetapi papan saya tidak mendukungnya. Saya memesan di Cina dan mengganti perisai dengan yang lain - pada en28j60 - itu menjadi lebih baik, tetapi tetap saja mereka menutup telepon secara berkala. Saya menambahkan modul relay ke controller, membawa daya ke papan Arduino melalui kontak yang biasanya tertutup di atasnya, dan salah satu papan Arduino menarik relai dengan frekuensi tertentu dan daya terputus, dan kemudian dipulihkan, namun, ini juga tidak selalu berfungsi, dan berkedip pada saat reboot. Lampu menyala,bahkan untuk beberapa detik, tetapi tetap saja. Inilah yang terlihat seperti pengontrol saat ini:



Dan kemudian diputuskan untuk sepenuhnya meninggalkan perisai ethernet. Saya mulai mencari fitur manajemen jarak jauh lainnya. Saya mencoba untuk menghubungkan arduins langsung ke server dan mengirim perintah melalui Serial.read () / Serial.print () - itu berfungsi setiap saat, stabilitas tidak tercapai karena papan reboot setiap kali diakses dari skrip di server. Saya membaca banyak tentang kesalahan seperti itu, saya baru menyadari bahwa itu terhubung dengan DTR, di suatu tempat mereka menulis bahwa Anda dapat menginisialisasi port dengan flag lain, memberikan contoh yang tidak bekerja untuk saya. Setelah beberapa saat, saya menemukan artikel tentang membuat adaptor USB-I2C dari seorang programmer USBAsp. Saya memutuskan - mengapa tidak? Saya memesan beberapa programmer seperti dari Cina - dan menunggu.

Dan seminggu yang lalu paket saya tiba. Salah satu programmer di-flash dengan i2c firmware usb kecil dan saya kembali duduk untuk menulis ulang kode. Di sini fitur protokol mulai muncul. Tentu saja, server adalah master, dan semua papan Arduino adalah budak.

Kode harus menyelesaikan tugas-tugas berikut:

- melaporkan status port yang diminta;
- beralih status port yang diminta;
- matikan atau hidupkan semua lampu.

Dan saya mengalami masalah. Saya dapat menggunakan perintah standar dari suite i2c-tools untuk berkomunikasi dengan papan Arduino. Ini tim

i2cget -y < > <>

dan

i2cset -y < > <> 0x00 <byte >

Sepertinya, dinilai oleh para lelaki, Anda bisa memberikan nilai kata, tetapi itu tidak berhasil bagi saya, atau saya salah di suatu tempat.

Masalahnya adalah, pertama, jika saya perlu mengganti status port tertentu, saya harus terlebih dahulu melewati nomor perintah yang bertanggung jawab untuk operasi ini, dan kemudian nomor port. Saya bahkan mencoba melakukan ini, mengirim 2 perintah, dan dalam kode untuk mengumpulkannya secara bergantian - tetapi itu jelek dan tidak rasional.

Masalah nomor dua - Arduino tidak dapat menjawab sesuatu saat dia menerima data. Ada dua metode pustaka kawat - onReceive () saat data diterima dari master dan onRequest () saat data diminta oleh master.

Jadi saya melakukan ini: server web memiliki 6 perintah:

  • perintah "1" - dapatkan status semua lampu
  • perintah "2" - dapatkan status pemblokiran semua sakelar
  • command "5" - nyalakan seluruh dunia
  • command "6" - matikan seluruh dunia

perintah yang dibentuk sebagai berikut: angka desimal dari formulir berikut <ratusan (1 atau 2) - alihkan lampu atau sakelar kunci> <nomor port (dari 0 hingga 99)>; misalnya, 105 - switch 5 port, 213 - switch 13 port lock. Perintah ini diterjemahkan ke dalam hex dan diteruskan ke Arduino, yang melakukan invers mengubah dan memahami apa yang perlu dilakukan.

Begini tampilannya di sisi server:

  ...
  if ($action == 3)
     $val_hex = dechex(intval($port) + 100);
  else
     $val_hex = dechex(intval($port) + 200);
  
  exec("sudo i2cset -y 7 $addr 0x00 0x$val_hex", $output);
  ...

Dan dari sisi Arduino:

void receiveEvent(int howMany) {
  byte bytes = Wire.available();
  int x = 0;
  for (byte i=1; i <= bytes; i=i+1) {
    x = Wire.read();
  }
  
  if (x == 1 or x == 2 or x == 5 or x == 6) {
    do_action(x, 0);
  } else {
    if ( x > 200) {
      do_action (4, x - 200);
    } else {
      do_action (3, x - 100);
    }
  }  
}

Terlihat sangat primitif, tetapi berhasil. Masalah kedua dipecahkan sebagai berikut. Inilah fungsi do_action:

void do_action(byte command, byte port) {
  byte value = 0;
  byte dvalue = 0;
  switch (command) {
    case 1:
      start_request = true;
      request_type = 1;
      current_port = 0;
      
      break;
    case 2:
      start_request = true;
      request_type = 2;
      current_port = 0;
      
      break;
    case 3:
      value = EEPROM.read(port);
      if(value==11) {
        digitalWrite(port, HIGH);
        EEPROM.write(port, 10);
      } else {
        digitalWrite(port, LOW);
        EEPROM.write(port, 11);
      }
      
      break;
    case 4:
      dvalue = EEPROM.read(port);
      if(dvalue==11) {
        EEPROM.write(port, 10);
      } else {
        EEPROM.write(port, 11);
      }
      
      break;
    case 5:
      for (byte i=0; i<cnt; i = i + 1) {
        digitalWrite(leds[i], LOW);
        EEPROM.write(leds[i], 11);
      }
      
      break;
    case 6:
      for (byte i=0; i<cnt; i = i + 1) {
        digitalWrite(leds[i], HIGH);
        EEPROM.write(leds[i], 10);
      }
      
      break;
    default:
      
    break;
  }
}

Dengan tim 3-6, semuanya jelas, tetapi tim 1 atau 2 dapat dijelaskan secara lebih rinci. Server pertama mengirim perintah yang diinginkan, dan ketika arduino menerima perintah 1 atau 2, bendera diinisialisasi:

  start_request = true;
  request_type = 1;
  current_port = 0;

Dan kemudian server mulai mengirim permintaan ke Arduino sebanyak port yang ingin di polling. Di sisi server:

function get_data($address, $action, $cnt) {
	exec("sudo i2cset -y 7 $address 0x00 0x0$action", $output);
	$tmp = @$output[0];
	while (strpos($tmp,"rror")!==false) {
		exec("sudo i2cset -y 7 $address 0x00 0x0$action", $output);
		$tmp = @$output[0];
	}
	$str = "";
	for ($i = 1; $i <= $cnt; $i++) {
		exec("sudo i2cget -y 7 $address", $output);
		$tmp = @$output[0];
		while (strpos($tmp,"rror")!==false) {
			exec("sudo i2cget -y 7 $address", $output);
			$tmp = @$output[0];
		}
		if ($tmp) {
			if (strpos($tmp,"1")!==false)
				$str .= "1";
			else
				$str .= "0";
		}
		unset($output);
		unset($tmp);
	}
			
	return $str;
}

$str = array();
$c = 1;
while ($c <= $tryes) {
	$tmp = get_data($addr, $action, $cnt);
	
	if (strlen($tmp) == $cnt)
		$str[] = $tmp;
	
	$c++;
}

$new_array = array_count_values($str);

asort($new_array);

$res = "";
$max = 0;
foreach ($new_array AS $key=>$val) {
	if ($val >= $max) {
		$res = $key;
		$max = $val;
	}
}

return preg_split('//', $res, -1, PREG_SPLIT_NO_EMPTY);

Singkatnya - kami membuat beberapa ($ tryes> 3) upaya untuk menginterogasi Arduino, kami mendapatkan garis yang terdiri dari 0 atau 1. Di mana-mana dengan perintah apa pun kami melihat jawabannya, jika ada kata Kesalahan - itu berarti ada kesalahan selama transfer dan Anda perlu mengulangi transfer . Beberapa upaya dilakukan untuk memastikan kebenaran dari string yang ditransmisikan, array tersebut diciutkan oleh string menggunakan metode array_count_values ​​($ str); dan pada akhirnya kita mendapatkan array dengan jumlah kemunculan dari baris yang sama, kita mendapatkan baris yang paling banyak kita terima dari arduino.

Dari sisi Arduino semuanya lebih sederhana:

void requestEvent() {
  if (request_type == 1) {
    byte value = EEPROM.read(leds[current_port]);
    if(value==11) {
      Wire.write(1);
    } else {
      Wire.write(0);
    }
    
    current_port = current_port + 1;
  } else if (request_type == 2) {
    byte dvalue = EEPROM.read(pins[current_port]);
    if(dvalue==11) {
      Wire.write(1);
    } else {
      Wire.write(0);
    }

    current_port = current_port + 1;
  }
}

Kode halaman web berisi kontrol:

<a class="lamp living_room" id="lamp0x4d3" rel='0x4d' onclick="lamp_click('0x4d',this.id, 3);" ></a>
<a class="lamp kitchen" id="lamp0x4d4" rel='0x4d' onclick="lamp_click('0x4d',this.id, 4);" ></a>
<a class="lamp children_main" id="lamp0x4d5" rel='0x4d' onclick="lamp_click('0x4d',this.id, 5);" ></a>
<a class="lamp children_second" id="lamp0x4d6" rel='0x4d' onclick="lamp_click('0x4d',this.id, 6);" ></a>
<a class="lamp sleeproom_main" id="lamp0x423" rel='0x42' onclick="lamp_click('0x42',this.id, 3);" ></a>
<a class="lamp sleeproom_lyuda" id="lamp0x424" rel='0x42' onclick="lamp_click('0x42',this.id, 4);" ></a>
<a class="lamp sleeproom_anton" id="lamp0x425" rel='0x42' onclick="lamp_click('0x42',this.id, 5);" ></a>

<a class="button button_living_room" id="button0x4d15" onclick="button_click('0x4d',this.id, 15);" ></a>
<a class="button button_kitchen" id="button0x4d14" onclick="button_click('0x4d',this.id, 14);" ></a>
<a class="button button_children_main" id="button0x4d16" onclick="button_click('0x4d',this.id, 16);" ></a>
<a class="button button_children_second" id="button0x4d17" onclick="button_click('0x4d',this.id, 17);" ></a>
<a class="button button_sleeproom_door1" id="button0x4212" onclick="button_click('0x42',this.id, 12);" ></a>
<a class="button button_sleeproom_door2" id="button0x4213" onclick="button_click('0x42',this.id, 13);" ></a>
<a class="button button_sleeproom_lyuda1" id="button0x4214" onclick="button_click('0x42',this.id, 14);" ></a>
<a class="button button_sleeproom_lyuda2" id="button0x4215" onclick="button_click('0x42',this.id, 15);" ></a>
<a class="button button_sleeproom_anton1" id="button0x4216" onclick="button_click('0x42',this.id, 16);" ></a>
<a class="button button_sleeproom_anton2" id="button0x4217" onclick="button_click('0x42',this.id, 17);" ></a>

Sebenarnya, saya secara eksplisit menunjukkan alamat papan yang perlu saya akses dan nomor port.

Oh ya, pengontrolnya terlihat seperti ini sekarang:



Setelah semuanya terpasang di tempatnya, semuanya dimulai pertama kali. Dan hari berikutnya, efek yang tidak dapat dipahami muncul - jika Anda menyalakan semua lampu di kamar, semua lampu di kamar mulai berkedip setiap 2-3 detik. Saya menghabiskan sepanjang malam memilih kode, tidak ada tiang seperti itu di bangku tes, jadi masalahnya bukan pada kode. Saya mengaduk-aduk sekelompok forum, dalam toga di salah satu dari mereka saya menemukan deskripsi gejala yang sama, memeriksa dugaan saya - dan masalahnya hilang. Dan intinya adalah bahwa saya memberi makan ketiga arduin dari catu daya komputer, 12V, dan freeduino lama diam-diam makan dan tidak bersenandung, dan arduino uno v3 tidak bisa, dan ketika semua relay dihidupkan, regulator daya dipanaskan sehingga Itu tidak mungkin disentuh. Mengurangi tegangan suplai menjadi 5V 2A - dan berfungsi sebagaimana mestinya.

Ada banyak rencana, kita harus menyelesaikan perbaikan di apartemen, koridor dan kamar mandi dengan toilet yang sesuai, dalam mimpiku aku ingin mengendalikan pemanas air dan setiap outlet, karena sekarang aku dapat menggantung arduin dalam jumlah banyak pada bus I2C dan masing-masing akan melakukan hal sendiri. Juga direncanakan untuk menambahkan relai pulsa ke rel din sehingga modul relai hanya mengontrol relai pulsa ini, dan sudah seluruh beban melewati yang terakhir. Karena ada keraguan serius tentang keandalan modul relay Cina. Tapi itu saja di masa depan.

Seperti yang dijanjikan, tautan ke github:

Antarmuka web yang samar
untuk Arduino

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


All Articles