Устройство собрано из минимального количества деталей — ESP-01S, ключа на транзисторе, инфракрасного светодиода и стабилизатора напряжения +3,3v и нескольких резисторов. Позволяет управлять вашим телевизором или приставкой (STB) через интернет по принципу интернета вещей. Идея создать такое устройство появилось после получения достаточно огромной базы данных кодов для пультов к TV / STB (более 500 моделей).
Приведённый ниже скетч позволяет работать схеме в обоих направлениях — как передавать инфракрасные посылки, так и принимать их по пину GPIO0 (можно не устанавливать). В этом случае принятые коды будут выводить в UART на скорости 9600 бод. Для успешной компиляции скетча необходимо подключить стандартные библиотеки ESP8266WiFi и IRremoteESP8266.
#include <Arduino.h> #include <assert.h> #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> #include <IRremoteESP8266.h> #include <IRrecv.h> #include <IRsend.h> #include <IRac.h> #include <IRtext.h> #include <IRutils.h> #include <EEPROM.h> #define ESSID eeprom_reads(0x10); #define EPASS eeprom_reads(0x30); // если нужен статический ip, то ставим 1 и ниже прописываем адреса #define STATIC 0 IPAddress ip(192,168,1,177); IPAddress gateway(192,168,1,1); IPAddress subnet(255,255,255,0); IRsend irsend(3); // GPIO IR pin=3 IRrecv irrecv(0, 1024, 50, true); // IR sensor pin=0 decode_results results; ESP8266WebServer server(80); const int led = LED_BUILTIN; const int btn = 0; void handleRoot() { String ans="undefined"; unsigned long cmd = 0x00000000; String proto = ""; if(server.args() and server.argName(0)=="cmd"){ cmd = str_to_long(server.arg(0)); proto = server.argName(1); if(proto=="RC5"){ irsend.sendRC5(cmd); }else if(proto=="SAMSUNG"){ irsend.sendSAMSUNG(cmd); }else{ // NEC - default irsend.sendNEC(cmd); } server.send(200, "text/html", "OK"); }else{ proto = String(random(10000,99999)); server.send(200, "text/html", "<html><head>" "<script src='https://conture.by/iresp/jquery.min.js'></script>" "<script src='https://conture.by/iresp/script.js?"+proto+"'></script>" "<link rel='stylesheet' href='https://conture.by/iresp/mdi/css/materialdesignicons.min.css' />" "<link type='text/css' rel='stylesheet' href='https://conture.by/iresp/styles.css?"+proto+"' />" "</head><body>" "...something went wrong" "</body>" "</html>\r\n"); } } void handleNotFound() { String message = "Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i = 0; i < server.args(); i++) { message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; } server.send(404, "text/plain", message); } void setup(void) { EEPROM.begin(512); Serial.begin(9600); char t=0; String essid = ESSID; String epass = EPASS; irsend.begin(); pinMode(btn, INPUT); pinMode(led, OUTPUT); WiFi.mode(WIFI_STA); digitalWrite(led, HIGH); // led off label1: if(EEPROM.read(0x0F)==1){ WiFi.begin(essid, epass); if(STATIC)WiFi.config(ip, gateway, subnet); Serial.println("\nESSID: "+essid); Serial.println("EPASS: "+epass); goto label3; } label2: WiFi.beginWPSConfig(); label3: while (WiFi.status() != WL_CONNECTED) { delay(200); Serial.print("."); digitalWrite(led, !digitalRead(led)); if(t==60){ t=0; goto label2; } t++; } digitalWrite(led, HIGH); // led off Serial.println("OK"); if(EEPROM.read(0x0F)!=1 or WiFi.SSID()!=essid or WiFi.psk()!=epass){ EEPROM.write(0x0F, 1); // признак того, что пароли сохранены eeprom_writes(0x10, WiFi.SSID()); eeprom_writes(0x30, WiFi.psk()); EEPROM.commit(); } MDNS.begin("iresp"); server.on("/", handleRoot); server.onNotFound(handleNotFound); server.begin(); digitalWrite(led, LOW); // lef on assert(irutils::lowLevelSanityCheck() == 0); irrecv.setUnknownThreshold(12); irrecv.setTolerance(kTolerance); irrecv.enableIRIn(); } void loop(void){ server.handleClient(); MDNS.update(); if (irrecv.decode(&results)) { digitalWrite(led, HIGH); delay(10); Serial.println(resultToSourceCode(&results)); digitalWrite(led, LOW); } } 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; } void eeprom_writes(int addr, String s){ int len = s.length(); EEPROM.write(addr, len); for(int i=1; i<=len; i++){ EEPROM.write(addr+i, s[i-1]); } } String eeprom_reads(int addr){ String s = ""; int len = EEPROM.read(addr); for (int i=1; i<=len; i++){ s += char(EEPROM.read(addr+i)); } return s; }
Идея логики работы устройства следующая. После программирования ESP-01S и сборки по схеме выше, необходимо подключиться по WiFi к вашему роутеру. Для этого нажимаем кнопку WPS на роутере и включаем собранное устройство. Попытка подключения — светодиод на ESP будет мигать. При успешном подключении — будет гореть постоянно (процесс можно наблюдать и по UART). Данные для входа сохраняются в EEPROM, поэтому следующее подключение произойдёт автоматически.
После того, как успешно подключились к сети, определим адрес назначенный роутером нашей ESP. Для этого пинганём адрес службы mDNS с доменом «iresp».
Теперь переходим по этому IP-адресу на телефоне или компьютере и вводим в строке название нашего пульта (например нам нужен пульт от MAG255)..
Так как памяти в ESP не так уж и много, а хотелось бы вместить всю базу данных пультов и сделать пульт по возможности красивым, то скрипты и БД залил на https://conture.by/iresp — откуда они и подкачиваются.
Корпус устройства для распечатки на 3д принтере в формате STL.