Pull to refresh

Bluetooth пульт для телевизора на arduino

Reading time12 min
Views34K
Продолжаем делать разные смарт/умные/bluetooth девайсы на ардуино. В прошлых статьях я рассказывал про bluetooth машинку и bluetooth вольтметр. сегодня речь пойдет о чем-то вроде bluetooth пульта для телевизора. Голосование на наиболее удачное название для такого девайса будет в конце статьи, а для начала предлагаю посмотреть видео как же этот девайс работает.



В статье я расскажу почему, как и из чего собирал этот девайс, про преимущества и недостатки его использования, а также пару слов о существующих аналогах.

Сначало о том, почему я решил сделать подобный девайс. Это, как мне кажется, очень важный вопрос, потому что большинство друзей, которым я рассказывал об этом устройстве спрашивают в первую очередь не о том, как оно работает, а о том, для чего я вообще сделал этот девайс. Началось все с того, что после долгого перерыва, связанного с появлением у меня высокоскоростного интернета, я решил включить телевизор и узнать измелилось ли там что-нибудь за те несколько лет, что я его не включал. Оказывается изменилось. Прежде всего у меня на телевизоре оказалось 63 канала, вместо 7-8 каналов, что были раньше. Это показалось хорошей новостью, пока я не понял, что смотреть я смогу лишь столько каналов из этих 63, сколько их номеров я смогу запомнить. То есть, если Вы не помните, на каком канале настроен Discovery, посмотреть Вы его фоктически не сможете, пока не перелистаете каналы по порядку. Даже если Вы помните номер нужного канала, нужно еще изловчиться нажать 2 кнопки пульта за определенное (короткое) время, попав по иногда стертым кнопкам пульта ДУ в темноте. В общем это ад, и поэтому я решил что-то с этим сделать.

Теперь перейдем непосредственно к девайсу, который получилось сделать. Схема довольно простая:



Компоненты:
Arduino nano
Bluetooth Module
ИК светодиод

Принцип работы тоже очень простой. Запускаем приложение на смартфоне, либо планшете, оно отправляет информацию с номером канала на заранее сопряженный bluetooth модуль. Этот модуль передает номер канала на ардуино, а ардуино генерирует нужный сигнал на 3 пин, имитируя тем самым штатный пульт ДУ. Надо сказать, что тема управления различными бытовыми приборами по ИК каналу с ардуино развита достаточно хорошо, и есть библиотека IRremote для ардуино, которая поддерживает большинство телевизоров и другой техники с ИК управлением.

Теперь к процессу изготовления bluetooth пульта. Чтобы узнать, какие сигналы ардуино должна отсылать на телевизор, нужно сначала отсканировать штатный пульт ДУ с помощью стандартного скетча библиотеки IRremote и ИК приемника. Пульт от моего телевизора LG получилось отсканировать сразу. Эти коды я прописал в
скетче
#include <IRremote.h>
IRsend irsend;
unsigned long a;
void setup() {
Serial.begin(9600);
Serial.setTimeout(4);
pinMode(ledPin, OUTPUT);
}
void S1() {irsend.sendNEC(0x20DF8877, 32);delay(200);}
void S2() {irsend.sendNEC(0x20DF48B7, 32);delay(200);}
void S3() {irsend.sendNEC(0x20DFC837, 32);delay(200);}
void S4() {irsend.sendNEC(0x20DF28D7, 32);delay(200);}
void S5() {irsend.sendNEC(0x20DFA857, 32);delay(200);}

void S6() {irsend.sendNEC(0x20DF6897, 32);delay(200);}
void S7() {irsend.sendNEC(0x20DFE817, 32);delay(200);}
void S8() {irsend.sendNEC(0x20DF18E7, 32);delay(200);}
void S9() {irsend.sendNEC(0x20DF9867, 32);delay(200);}
void S0() {irsend.sendNEC(0x20DF08F7, 32);delay(200);}

void Son() {irsend.sendNEC(0x20DF10EF, 32);}

void loop()
{
if (Serial.available())
{ a = Serial.parseInt();
if (a==1) {S1();}
if (a==2) {S2();}
if (a==3) {S3();}
if (a==4) {S4();}
if (a==5) {S5();}
if (a==6) {S6();}
if (a==7) {S7();}
if (a==8) {S8();}
if (a==9) {S9();}
if (a==10) {S1();S0();}

if (a==11) {S1();S1();}
if (a==12) {S1();S2();}
if (a==13) {S1();S3();}
if (a==14) {S1();S4();}
if (a==15) {S1();S5();}
if (a==16) {S1();S6();}
if (a==17) {S1();S7();}
if (a==18) {S1();S8();}
if (a==19) {S1();S9();}
if (a==20) {S2();S0();}

if (a==21) {S2();S1();}
if (a==22) {S2();S2();}
if (a==23) {S2();S3();}
if (a==24) {S2();S4();}
if (a==25) {S2();S5();}
if (a==26) {S2();S6();}
if (a==27) {S2();S7();}
if (a==28) {S2();S8();}
if (a==29) {S2();S9();}
if (a==30) {S3();S0();}

if (a==31) {S3();S1();}
if (a==32) {S3();S2();}
if (a==33) {S3();S3();}
if (a==34) {S3();S4();}
if (a==35) {S3();S5();}
if (a==36) {S3();S6();}
if (a==37) {S3();S7();}
if (a==38) {S3();S8();}
if (a==39) {S3();S9();}
if (a==40) {S4();S0();}

if (a==41) {S4();S1();}
if (a==42) {S4();S2();}
if (a==43) {S4();S3();}
if (a==44) {S4();S4();}
if (a==45) {S4();S5();}
if (a==46) {S4();S6();}
if (a==47) {S4();S7();}
if (a==48) {S4();S8();}
if (a==49) {S4();S9();}
if (a==50) {S5();S0();}

if (a==51) {S5();S1();}
if (a==52) {S5();S2();}
if (a==53) {S5();S3();}
if (a==54) {S5();S4();}
if (a==55) {S5();S5();}
if (a==56) {S5();S6();}
if (a==57) {S5();S7();}
if (a==58) {S5();S8();}
if (a==59) {S5();S9();}
if (a==60) {S6();S0();}

if (a==61) {S6();S1();}
if (a==62) {S6();S2();}
if (a==63) {S6();S3();}
if (a==64) {S6();S4();}
if (a==65) {S6();S5();}
if (a==66) {Son();}
if (a==67) {irsend.sendNEC(0x807F48B7, 32);}//прибавить звук
if (a==68) {irsend.sendNEC(0x807FC837, 32);}//убавить звук

}
}


Как выяснилось потом, эти коды подходят и к другим телевизорам LG.

Чуть позже я сделал такой же bluetooth пульт для телевизора Sony. Коды кнопок пультов Sony тоже считываются легко, но нужно знать, что у этой марки каждый сигнал повторяется 3 раза, а стандартный скетч для считывания библиотеки IRremote этого не «замечает». Поэтому в скетче нужно их повторить 3 раза. Скетч для работы с телевизором Sony
тут
#include <IRremote.h>
IRsend irsend;
int ledPin = 13;
unsigned long a;
void setup() {
Serial.begin(9600);
Serial.setTimeout(4);
pinMode(ledPin, OUTPUT);
}
void S1() {irsend.sendSony(0x10, 12);delay(100);irsend.sendSony(0x10, 12);delay(100);irsend.sendSony(0x10, 12);delay(1000);}
void S2() {irsend.sendSony(0x810, 12);delay(100);irsend.sendSony(0x810, 12);delay(100);irsend.sendSony(0x810, 12);delay(1000);}
void S3() {irsend.sendSony(0x410, 12);delay(100);irsend.sendSony(0x410, 12);delay(100);irsend.sendSony(0x410, 12);delay(1000);}
void S4() {irsend.sendSony(0xC10, 12);delay(100);irsend.sendSony(0xC10, 12);delay(100);irsend.sendSony(0xC10, 12);delay(1000);}
void S5() {irsend.sendSony(0x210, 12);delay(100);irsend.sendSony(0x210, 12);delay(100);irsend.sendSony(0x210, 12);delay(1000);}

void S6() {irsend.sendSony(0xA10, 12);delay(100);irsend.sendSony(0xA10, 12);delay(100);irsend.sendSony(0xA10, 12);delay(1000);}
void S7() {irsend.sendSony(0x610, 12);delay(100);irsend.sendSony(0x610, 12);delay(100);irsend.sendSony(0x610, 12);delay(1000);}
void S8() {irsend.sendSony(0xE10, 12);delay(100);irsend.sendSony(0xE10, 12);delay(100);irsend.sendSony(0xE10, 12);delay(1000);}
void S9() {irsend.sendSony(0x110, 12);delay(100);irsend.sendSony(0x110, 12);delay(100);irsend.sendSony(0x110, 12);delay(1000);}
void S0() {irsend.sendSony(0x910, 12);delay(100);irsend.sendSony(0x910, 12);delay(100);irsend.sendSony(0x910, 12);delay(1000);}

void Son() {irsend.sendSony(0xA90, 12);delay(100);irsend.sendSony(0xA90, 12);delay(100);irsend.sendSony(0xA90, 12);delay(1000);}

void loop()
{
if (Serial.available())
{ a = Serial.parseInt();
if (a==1) {S1();}
if (a==2) {S2();}
if (a==3) {S3();}
if (a==4) {S4();}
if (a==5) {S5();}
if (a==6) {S6();}
if (a==7) {S7();}
if (a==8) {S8();}
if (a==9) {S9();}
if (a==10) {S1();S0();}

if (a==11) {S1();S1();}
if (a==12) {S1();S2();}
if (a==13) {S1();S3();}
if (a==14) {S1();S4();}
if (a==15) {S1();S5();}
if (a==16) {S1();S6();}
if (a==17) {S1();S7();}
if (a==18) {S1();S8();}
if (a==19) {S1();S9();}
if (a==20) {S2();S0();}

if (a==21) {S2();S1();}
if (a==22) {S2();S2();}
if (a==23) {S2();S3();}
if (a==24) {S2();S4();}
if (a==25) {S2();S5();}
if (a==26) {S2();S6();}
if (a==27) {S2();S7();}
if (a==28) {S2();S8();}
if (a==29) {S2();S9();}
if (a==30) {S3();S0();}

if (a==31) {S3();S1();}
if (a==32) {S3();S2();}
if (a==33) {S3();S3();}
if (a==34) {S3();S4();}
if (a==35) {S3();S5();}
if (a==36) {S3();S6();}
if (a==37) {S3();S7();}
if (a==38) {S3();S8();}
if (a==39) {S3();S9();}
if (a==40) {S4();S0();}

if (a==41) {S4();S1();}
if (a==42) {S4();S2();}
if (a==43) {S4();S3();}
if (a==44) {S4();S4();}
if (a==45) {S4();S5();}
if (a==46) {S4();S6();}
if (a==47) {S4();S7();}
if (a==48) {S4();S8();}
if (a==49) {S4();S9();}
if (a==50) {S5();S0();}

if (a==51) {S5();S1();}
if (a==52) {S5();S2();}
if (a==53) {S5();S3();}
if (a==54) {S5();S4();}
if (a==55) {S5();S5();}
if (a==56) {S5();S6();}
if (a==57) {S5();S7();}
if (a==58) {S5();S8();}
if (a==59) {S5();S9();}
if (a==60) {S6();S0();}

if (a==61) {S6();S1();}
if (a==62) {S6();S2();}
if (a==63) {S6();S3();}
if (a==64) {S6();S4();}
if (a==65) {
irsend.sendSony(0x290, 12); // Sony TV mute code
delay(100);
irsend.sendSony(0x290, 12); // Sony TV mute code
delay(100);
irsend.sendSony(0x290, 12); // Sony TV mute code
delay(100);
}
if (a==66) {
irsend.sendSony(0xa90, 12); // Sony TV power code
delay(100);
irsend.sendSony(0xa90, 12); // Sony TV power code
delay(100);
irsend.sendSony(0xa90, 12); // Sony TV power code
delay(100);
}
if (a==67) {
irsend.sendSony(0x490, 12); // Sony TV vol+
delay(100);
irsend.sendSony(0x490, 12); // Sony T
delay(100);
irsend.sendSony(0x490, 12); // Sony TV vol+
delay(100);
}
if (a==68) {
irsend.sendSony(0xc90, 12); // Sony TV vol-
delay(100);
irsend.sendSony(0xc90, 12); // Sony T
delay(100);
irsend.sendSony(0xc90, 12); // Sony TV vol-
delay(100);
}
if (a==69) {S6();S9();}
if (a==70) {S7();S0();}

if (a==71) {S7();S1();}
if (a==72) {S7();S2();}
if (a==73) {S7();S3();}
if (a==74) {S7();S4();}
if (a==75) {S7();S5();}
if (a==76) {S7();S6();}
if (a==77) {S7();S7();}
if (a==78) {S7();S8();}
if (a==79) {S7();S9();}
if (a==80) {S8();S0();}

if (a==81) {S8();S1();}
if (a==82) {S8();S2();}
if (a==83) {S8();S3();}
if (a==84) {S8();S4();}
if (a==85) {S8();S5();}
if (a==86) {S8();S6();}
if (a==87) {S8();S7();}
if (a==88) {S8();S8();}
if (a==89) {S8();S9();}
if (a==90) {S9();S0();}

if (a==91) {S9();S1();}
if (a==92) {S9();S2();}
if (a==93) {S9();S3();}
if (a==94) {S9();S4();}
if (a==95) {S9();S5();}
if (a==96) {S9();S6();}
if (a==97) {S9();S7();}
if (a==98) {S9();S8();}
if (a==99) {S9();S9();}
if (a==100) {Son();}

}
}


Видео с демонстрацией роботы с Sony:



С телевизорами samsung ситуация чуть сложнее. библиотека IRremote сигналы их пультов не распознает, поэтому их приходится просто отсылать в том же виде, в каком они приходят в формате RAW.
Скетч для работы с телевизором самсунг
#include <IRremote.h>
IRsend irsend;
unsigned long a;
void setup() {
Serial.begin(9600);
Serial.setTimeout(4);
pinMode(ledPin, OUTPUT);
}

unsigned int A_one[78]={4450,4550,400,1800,450,650,450,1800,450,600,500,650,450,650,450,700,450,650,450,1750,450,650,500,1750,450,650,450,650,500,650,450,650,450,700,450,650,450,650,450,1750,450,650,500,650,450,650,500,650,450,650,450,1750,450,1750,500,650,450,1700,500,1750,450,1750,450,1800,450,1700,450};
unsigned int A_two[78]={4450,4550,450,1750,450,650,500,1750,500,600,450,650,450,650,500,650,450,650,500,1700,500,650,450,1800,450,600,500,650,450,650,450,650,500,650,450,1750,450,650,500,1750,450,650,450,650,450,700,450,650,450,650,450,700,450,1750,450,650,450,1700,500,1750,500,1750,450,1750,500,1650,500};
unsigned int A_three[78]={4450,4500,450,1750,450,700,450,1750,450,650,450,650,500,650,450,650,450,650,500,1750,450,650,450,1750,500,600,500,650,450,650,450,650,500,650,450,650,450,1750,500,1750,450,650,450,650,500,650,450,650,450,650,450,1750,500,650,450,650,500,1700,450,1800,450,1700,500,1750,500,1650,500};
unsigned int A_four[78]={4450,4550,450,1750,450,700,450,1750,450,650,450,650,500,650,450,650,450,650,500,1700,500,650,450,1750,500,600,500,650,450,650,450,650,500,650,450,650,450,650,500,650,450,1700,500,600,500,650,450,650,500,600,500,1750,450,1750,500,1750,450,600,500,1750,500,1700,500,1750,500,1650,500};
unsigned int A_five[78]={4450,4550,450,1750,450,650,500,1750,450,650,450,650,500,650,450,650,450,650,500,1750,450,650,450,1750,500,600,500,650,450,650,450,650,500,650,450,1750,450,650,500,650,450,1700,500,650,450,650,450,650,450,700,450,650,450,1750,500,1750,450,650,450,1750,500,1750,450,1750,500,1650,500};

unsigned int A_six[78]={4400,4550,450,1800,400,700,400,1800,450,650,450,700,400,700,450,650,450,650,500,1750,450,650,450,1750,500,600,500,650,450,650,450,700,400,700,450,650,450,1750,500,650,450,1700,500,650,450,650,450,700,400,700,450,1750,450,650,450,1800,450,650,450,1750,500,1750,450,1750,450,1700,500};
unsigned int A_seven[78]={4450,4550,450,1750,450,650,450,1800,450,650,450,650,450,650,500,650,450,650,450,1750,500,600,500,1750,500,600,500,600,500,650,450,650,500,600,500,650,450,650,500,1750,450,1700,500,600,500,650,450,650,450,650,500,1750,450,1750,500,600,500,650,450,1700,550,1700,500,1750,450,1700,500};
unsigned int A_eight[78]={4400,4550,450,1750,450,650,450,1800,450,650,450,650,450,700,400,650,500,650,450,1750,450,700,450,1750,500,600,450,700,450,650,450,650,450,700,450,1750,450,650,450,1800,450,1700,500,650,450,650,450,700,450,600,500,650,450,1750,500,650,450,650,450,1750,450,1800,400,1800,450,1700,450};
unsigned int A_nine[78]={4450,4500,450,1750,500,650,450,1800,450,600,450,650,500,650,450,650,450,700,450,1750,450,650,450,1800,450,650,450,650,450,650,500,600,500,650,450,650,500,1750,450,1750,500,1700,450,650,500,650,450,650,450,650,450,1800,450,650,450,650,450,650,450,1800,450,1750,450,1750,500,1650,500};
unsigned int A_zero[78]={4450,4500,500,1750,450,650,450,1800,450,650,450,650,450,650,500,650,450,650,450,1750,450,650,500,1750,500,600,450,650,500,650,450,650,450,650,500,1750,450,650,450,650,500,650,450,1750,450,650,450,650,500,650,450,650,450,1750,500,1750,450,1750,450,650,450,1750,500,1750,450,1700,450};

unsigned int A_w[78]={4450,4550,450,1750,450,650,500,1750,450,650,450,650,450,650,500,650,450,650,500,1700,500,600,500,1750,500,600,500,650,450,650,450,650,500,650,450,650,450,650,500,600,500,600,500,1750,500,600,500,1700,500,650,450,1750,450,1800,450,1750,450,1750,450,650,450,1750,500,650,450,1700,500};
unsigned int A_on[78]={4450,4550,450,1750,450,650,450,1800,450,650,450,650,450,650,450,700,450,650,450,1750,450,700,450,1750,500,600,450,650,500,650,450,650,450,700,450,650,450,1750,450,650,450,700,450,650,450,650,500,650,450,650,450,1750,450,700,450,1750,450,1750,400,1800,450,1800,400,1800,450,1700,450};

void S1() {irsend.sendRaw(A_one,78,38);delay(500);}
void S2() {irsend.sendRaw(A_two,78,38);delay(500);}
void S3() {irsend.sendRaw(A_three,78,38);delay(500);}
void S4() {irsend.sendRaw(A_four,78,38);delay(500);}
void S5() {irsend.sendRaw(A_five,78,38);delay(500);}

void S6() {irsend.sendRaw(A_six,78,38);delay(500);}
void S7() {irsend.sendRaw(A_seven,78,38);delay(500);}
void S8() {irsend.sendRaw(A_eight,78,38);delay(500);}
void S9() {irsend.sendRaw(A_nine,78,38);delay(500);}
void S0() {irsend.sendRaw(A_zero,78,38);delay(500);}

void Son() {irsend.sendRaw(A_on,78,38);delay(500);}

void loop()
{
if (Serial.available())
{ a = Serial.parseInt();

if (a==101) {Son ();}
if (a==102) {S2();}
if (a==103) {S3();}

if (a==1) {S1();}
if (a==2) {S2();}
if (a==3) {S3();}
if (a==4) {S4();}
if (a==5) {S5();}
if (a==6) {S6();}
if (a==7) {S7();}
if (a==8) {S8();}
if (a==9) {S9();}
if (a==10) {S1();S0();}

if (a==11) {S1();S1();}
if (a==12) {S1();S2();}
if (a==13) {S1();S3();}
if (a==14) {S1();S4();}
if (a==15) {S1();S5();}
if (a==16) {S1();S6();}
if (a==17) {S1();S7();}
if (a==18) {S1();S8();}
if (a==19) {S1();S9();}
if (a==20) {S2();S0();}

if (a==21) {S2();S1();}
if (a==22) {S2();S2();}
if (a==23) {S2();S3();}
if (a==24) {S2();S4();}
if (a==25) {S2();S5();}
if (a==26) {S2();S6();}
if (a==27) {S2();S7();}
if (a==28) {S2();S8();}
if (a==29) {S2();S9();}
if (a==30) {S3();S0();}

if (a==31) {S3();S1();}
if (a==32) {S3();S2();}
if (a==33) {S3();S3();}
if (a==34) {S3();S4();}
if (a==35) {S3();S5();}
if (a==36) {S3();S6();}
if (a==37) {S3();S7();}
if (a==38) {S3();S8();}
if (a==39) {S3();S9();}
if (a==40) {S4();S0();}

if (a==41) {S4();S1();}
if (a==42) {S4();S2();}
if (a==43) {S4();S3();}
if (a==44) {S4();S4();}
if (a==45) {S4();S5();}
if (a==46) {S4();S6();}
if (a==47) {S4();S7();}
if (a==48) {S4();S8();}
if (a==49) {S4();S9();}
if (a==50) {S5();S0();}

if (a==51) {S5();S1();}
if (a==52) {S5();S2();}
if (a==53) {S5();S3();}
if (a==54) {S5();S4();}
if (a==55) {S5();S5();}
if (a==56) {S5();S6();}
if (a==57) {S5();S7();}
if (a==58) {S5();S8();}
if (a==59) {S5();S9();}
if (a==60) {S6();S0();}

if (a==61) {S6();S1();}
if (a==62) {S6();S2();}
if (a==63) {S6();S3();}
if (a==64) {S6();S4();}
if (a==65) {S6();S5();}
if (a==66) {S6();S6();}
if (a==67) {S6();S7();}
if (a==68) {S6();S8();}
if (a==69) {S6();S9();}
if (a==70) {S7();S0();}

if (a==71) {S7();S1();}
if (a==72) {S7();S2();}
if (a==73) {S7();S3();}
if (a==74) {S7();S4();}
if (a==75) {S7();S5();}
if (a==76) {S7();S6();}
if (a==77) {S7();S7();}
if (a==78) {S7();S8();}
if (a==79) {S7();S9();}
if (a==80) {S8();S0();}

if (a==81) {S8();S1();}
if (a==82) {S8();S2();}
if (a==83) {S8();S3();}
if (a==84) {S8();S4();}
if (a==85) {S8();S5();}
if (a==86) {S8();S6();}
if (a==87) {S8();S7();}
if (a==88) {S8();S8();}
if (a==89) {S8();S9();}
if (a==90) {S9();S0();}

if (a==91) {S9();S1();}
if (a==92) {S9();S2();}
if (a==93) {S9();S3();}
if (a==94) {S9();S4();}
if (a==95) {S9();S5();}
if (a==96) {S9();S6();}
if (a==97) {S9();S7();}
if (a==98) {S9();S8();}
if (a==99) {S9();S9();}
if (a==100) {S1();S0();S0(); }

}
}


Демонстрация работы тут:



С ардуино разобрались, теперь переходим к Android. Приложение проще всего делать используя среду визуальной разработки android-приложений App Inventor 2, хотя тут кому как удобнее. Приложение должно обладать простым функционалом: подключаться к сопряженному bluetooth модулю и отправлять на него номер канала, на который нужно переключить. Дизайн моего приложения получился очень простой.



Если кто-то захочет сделать такое же приложение, я снял видео, в котором подробно объясняю как и что нужно для этого делать. Разобраться сможет даже тот, кто никогда не программировал под андроид. (для просмотра нужно перейти на ютуб)



Теперь пара слов о преимуществах и недостатках моего bluetooth пульта ДУ. Полезность данного девайса для общества вызывает серьезные сомнения, впрочем как и полезность других смарт/умных/bluetooth девайсов, таких, например, как «умная» рулетка, Bluetooth-стикер и «умный» магнит на холодильник. Но лично мне bluetooth пульт немного облегчает жизнь. Если раньше я вообще не смотрел телевизор, то сейчас включаю иногда, причем только со смартфона или планшета, смотря что лежит под рукой.

Вообще с подобной схемой можно управлять не только телевизором, а всеми приборами, которые управляются, но это уже немного другая история.
P.S. Сборник из более 100 обучающих материалов по ардуино для начинающих и профи тут
P.P.S. Онлайн курс по ардуино на гиктаймс здесь.
И закончить хочу опросом, который обещал в начале статьи.
Only registered users can participate in poll. Log in, please.
Как Вы считаете, как лучше назвать этот девайс?
58.72% bluetooth пульт64
20.18% смарт пульт22
7.34% умный пульт8
7.34% «умный» пульт8
6.42% свой вариант в комментариях7
109 users voted. 52 users abstained.
Tags:
Hubs:
Total votes 4: ↑4 and ↓0+4
Comments15

Articles