Ethernet IR remote controller

Eth_IR_ControllerНесмотря на тотальную цифровизацию головных станций, нередко у операторов трудятся старички-приставки, управление которых возможно только через пульт ДУ. Данный проект позволяет подавать инфракрасные команды на такие устройства через локальную сеть. Как вариант также можно управлять и кондиционером.

Демо работы — https://youtu.be/d0SwnBgk0hY

Для компиляции проекта, необходимо предварительно установить библиотеки: Ethercard и Infrared. Схема подключения к Arduino Pro Mini (3,3V на 8 MHz) ниже..

photo_2022-07-18_19-25-52

Устройство принимает команды по веб-адресу типа http://192.168.1.168/hE718BF00 , где E718BF00 — это команда в духе NEC-стандарта (на нём работают большинство пультов). Для усиления площади покрытия можно использовать два ИК-диода включённых последовательно. Ограничивающий резистор в этом случае ставим около 50 Ом.

Если смотреть логическим анализатором, то ИК-посылка выглядит как на скрине ниже. Импульс с короткой скважностью около 564 мксек — это «НОЛЬ», с длинной (1692 мксек) — «ЕДИНИЦА». Чтобы получить человекоподобное число из 4 байт, эту последовательность нулей и единиц надо зеркально отразить. Т.е. последний бит на скрине должен быть первым, а первый — последним.

photo_2022-07-17_09-22-06

Скетч, заливаемый через программу 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;
}

 

Запись опубликована в рубрике C++, Автоматика, Программирование, Радиолюбитель, Телевидение с метками , , . Добавьте в закладки постоянную ссылку.

Добавить комментарий