Несмотря на тотальную цифровизацию головных станций, нередко у операторов трудятся старички-приставки, управление которых возможно только через пульт ДУ. Данный проект позволяет подавать инфракрасные команды на такие устройства через локальную сеть. Как вариант также можно управлять и кондиционером.
Демо работы — https://youtu.be/d0SwnBgk0hY
Для компиляции проекта, необходимо предварительно установить библиотеки: Ethercard и Infrared. Схема подключения к Arduino Pro Mini (3,3V на 8 MHz) ниже..
Устройство принимает команды по веб-адресу типа http://192.168.1.168/hE718BF00 , где E718BF00 — это команда в духе NEC-стандарта (на нём работают большинство пультов). Для усиления площади покрытия можно использовать два ИК-диода включённых последовательно. Ограничивающий резистор в этом случае ставим около 50 Ом.
Если смотреть логическим анализатором, то ИК-посылка выглядит как на скрине ниже. Импульс с короткой скважностью около 564 мксек — это «НОЛЬ», с длинной (1692 мксек) — «ЕДИНИЦА». Чтобы получить человекоподобное число из 4 байт, эту последовательность нулей и единиц надо зеркально отразить. Т.е. последний бит на скрине должен быть первым, а первый — последним.
Скетч, заливаемый через программу Arduino IDE следующий:
#include <EtherCard.h> #include <IrSenderPwm.h> #define TCP_FLAGS_FIN_V 1 //as declared in net.h #define TCP_FLAGS_ACK_V 0x10 //as declared in net.h #define PROGRAM_NAME "Ethernet IR Remote Controller" static byte myip[] = { 192,168,1,168 }; static byte gwip[] = { 192,168,1,1 }; static byte mymac[] = { 0x74,0x68,0x69,0x2D,0x15,0x39 }; byte Ethernet::buffer[255]; // tcp ip send and receive buffer const char header[] PROGMEM = "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"; const char index[] PROGMEM = "<html><head><title>" PROGRAM_NAME "</title></head><body><h1>" PROGRAM_NAME "</h1><a href='/hE718BF00'>ZALA CH+</a></body></html>"; const char ok[] PROGMEM = "OK"; const char nok[] PROGMEM = "NOK"; microseconds_t arr[80] = {0}; static IrSender* irSender; void setup(){ ether.begin(sizeof Ethernet::buffer, mymac , SS); ether.staticSetup(myip, gwip); irSender = IrSenderPwm::getInstance(true, 3U); } void loop(){ dutycycle_t dutyCycle; dutyCycle = static_cast<dutycycle_t>(random(20,80)); word pos = ether.packetLoop(ether.packetReceive()); if (pos) { char* data = (char *) Ethernet::buffer + pos; if (strncmp("GET / ", data, 6) == 0) { ether.httpServerReplyAck(); // send ack to the request memcpy_P(ether.tcpOffset(), header, sizeof header); // send first packet and not send the terminate flag ether.httpServerReply_with_flags(sizeof header - 1,TCP_FLAGS_ACK_V); memcpy_P(ether.tcpOffset(), index, sizeof index); // send second packet and not send the terminate flag ether.httpServerReply_with_flags(sizeof index - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); }else if (strncmp("GET /h", data, 6) == 0) { bool f = true; int i = 0; char a; String str = ""; for(a=6; a<14; a++){ if(data[a]==' ')break; str += (char)data[a]; i++; } unsigned long l = str_to_long(str); str = String(l, BIN); i=i*4-1; // one 0xA - have 4 bits arr[0] = 9024; arr[1] = 4512; for(a=2; a<80; a+=2){ arr[a] = 0; arr[a+1] = 0; if(f){ arr[a] = 564; switch((char)str[i]){ case '0': arr[a+1] = 564; break; case '1': arr[a+1] = 1692; break; default: arr[a+1] = 39756; // end f = false; } i--; } } static const IrSequence irSequence(arr, sizeof(arr) / sizeof(microseconds_t)); irSender->send(irSequence, 38400U, dutyCycle); ether.httpServerReplyAck(); // send ack to the request memcpy_P(ether.tcpOffset(), header, sizeof header); // send first packet and not send the terminate flag ether.httpServerReply_with_flags(sizeof header - 1,TCP_FLAGS_ACK_V); memcpy_P(ether.tcpOffset(), ok, sizeof ok); // send first packet and not send the terminate flag ether.httpServerReply_with_flags(sizeof ok - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); }else{ ether.httpServerReplyAck(); // send ack to the request memcpy_P(ether.tcpOffset(), header, sizeof header); // send first packet and not send the terminate flag ether.httpServerReply_with_flags(sizeof header - 1,TCP_FLAGS_ACK_V); memcpy_P(ether.tcpOffset(), nok, sizeof nok); // send first packet and not send the terminate flag ether.httpServerReply_with_flags(sizeof nok - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); } } } unsigned long str_to_long(String str){ unsigned long ansver = 0; for(byte n = 0; n < str.length(); n++){ if((byte(str.charAt(n) ) >= 0x30) && (byte(str.charAt(n) ) <= 0x39)){//цифры ASCII 0 - 9 ansver |= ((byte(str.charAt(n) )- 0x30)); } if((byte(str.charAt(n) ) >= 0x41) && (byte(str.charAt(n) ) <= 0x46)){//символы ASCII A - F ansver |= ((byte(str.charAt(n) )- 0x41 + 10)); } if((byte(str.charAt(n) ) >= 0x61) && (byte(str.charAt(n) ) <= 0x66)){//символы ASCII a - f ansver |= ((byte(str.charAt(n) )- 0x61 + 10)); } if(n < (str.length() - 1) ){ ansver = ansver << 4; } } return ansver; }