В теории просто, подключаем esp8266 (ценой около 2 долларов у китайцев) к инфракрасном светодиоду, заливаем прошивку и готово.
На практике оказалось все несколько сложнее, т.к. у меня ревизия esp-01 пришлось припаять (примерно так) проводок к ножке микросхемы размером 5*5мм, вывести дополнительный GPIO. Рекомендую использовать ревизию постарше, например ESP-12.
Читателям не знакомым с esp8266 предлагаю ознакомится этой статьей.
Компоненты и модули
* Esp8266 ревизии esp-01
* FT232RL: USB to Serial 232 TTL Adapter + провода для подключения
* Фотоприемник Tsop 4838
* Регулятор 3.3v
* Транзистор S9014
* Светодиод инфракрасный 5013IRAB (длина волны 940 nm)
* Резистор 330ом
* Проектная плата
* Паяльник, припой, флюс.
* Для работы с IR используется замечательная библиотека IRremoteESP8266. Авторы Mark Szabo, Sebastien Warin, Ken Shirriff.
Сохранение кодов
* Подключаем фотоприемник, VCC на +3.3, GND на ноль, OUT на GPIO.
* Открываем пример для дампа кодов из нашей библиотеки \IRremoteESP8266\examples\IRrecvDump\IRrecvDump.ino
* Если надо — меняем номер пина к которому мы подключили OUT фотоприемника (строка «int RECV_PIN = 2;»).
* Заливаем прошивку. Подключаемся к выводу модуля. Поочередно зажимаем кнопки пульта для дампа кодов.
Для бризера Tion O2 у меня получились такие кода:
Down
16711935
Decoded NEC: FF00FF (32 bits)
— Up
16724175
Decoded NEC: FF30CF (32 bits)
— Set
16722135
Decoded NEC: FF28D7 (32 bits)
— Power
16720095
Decoded NEC: FF20DF (32 bits)
Фотоприемник больше не нужен, пока не потребуется «сграбить» кода другого пульта.
Управление устройством
* Подключаем ИК светодиод по схеме.
(Картинка заимствована у Fritzing)
GPIO можно использовать другой. От напряжения 3.3v светодиод так-же нормально работает.
UPD: Как справедливо заметили в комментариях желательно использовать токоограничивающий резистор.
* Демо прошивка с сервером находится тут
\IRremoteESP8266\examples\IRServer\IRServer.ino
* Меняем в ней название и пароль вашей точки доступа, чтобы esp мог подключиться к ней. А так-же номер используемого GPIO
const char* ssid = ".....";
const char* password = ".....";
IRsend irsend(0);
* Прошиваем модуль.
* При подключении в консоль будет выведен IP адрес выделенный esp.
Теперь можно отправлять кода вводя в броузере адрес вида 192.168.1.1/ir?code=16720095 (просто подставьте нужный IP и код).
/*
* IRremoteESP8266: IRServer - demonstrates sending IR codes controlled from a webserver
* An IR LED must be connected to ESP8266 pin 0.
* Version 0.1 June, 2015
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <IRremoteESP8266.h>
const char* ssid = "FFFF";
const char* password = "XXXX";
unsigned long last_cmd_send_time = 0;
MDNSResponder mdns;
ESP8266WebServer server(80);
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
// IRsend irsend(2);
IRsend irsend(13);
void handleRoot() {
server.send(200, "text/html", "<html><head> <title>ESP8266 Demo (Web Update)</title></head><body><h1>Hello from ESP8266, you can send NEC encoded IR signals from here!</h1><p><a href=\"ir?code=16769055\">Send 0xFFE01F</a></p><p><a href=\"ir?code=16429347\">Send 0xFAB123</a></p><p><a href=\"ir?code=16771222\">Send 0xFFE896</a></p></body></html>");
}
void handleIr(){
for (uint8_t i=0; i<server.args(); i++){
if(server.argName(i) == "code")
{
unsigned long code = server.arg(i).toInt();
irsend.sendNEC(code, 32);
}
}
handleRoot();
}
void handleSeq(){
unsigned long code = 0;
unsigned long cnt = 0;
unsigned long dl = 0;
unsigned long nwt = 0;
for (uint8_t i=0; i<server.args(); i++){
if(server.argName(i) == "code")
{
code = server.arg(i).toInt();
}
if(server.argName(i) == "count")
{
cnt = server.arg(i).toInt();
}
if(server.argName(i) == "delay")
{
dl = server.arg(i).toInt();
}
if(server.argName(i) == "need_wait")
{
nwt = server.arg(i).toInt();
}
}
if (nwt > 0){
unsigned long wt = millis() - last_cmd_send_time;
if (wt < nwt && wt > 0) {
delay(nwt - wt);
}
}
if (code != 0) {
for (uint8_t i=0; i<cnt; i++){
irsend.sendNEC(code, 32);
delay(dl);
}
}
last_cmd_send_time = millis();
handleRoot();
}
void handleNotFound(){
String message = "File 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){
irsend.begin();
Serial.begin(115200);
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (mdns.begin("esp8266", WiFi.localIP())) {
Serial.println("MDNS responder started");
}
server.on("/", handleRoot);
server.on("/ir", handleIr);
server.on("/seq", handleSeq);
server.on("/inline", [](){
server.send(200, "text/plain", "this works as well");
});
server.on("/update", HTTP_GET, [](){
server.sendHeader("Connection", "close");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/html", serverIndex);
});
server.on("/update", HTTP_POST, [](){
server.sendHeader("Connection", "close");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
ESP.restart();
},[](){
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
Serial.setDebugOutput(true);
WiFiUDP::stopAll();
Serial.printf("Update: %s\n", upload.filename.c_str());
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if(!Update.begin(maxSketchSpace)){//start with max available size
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_WRITE){
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
Update.printError(Serial);
}
} else if(upload.status == UPLOAD_FILE_END){
if(Update.end(true)){ //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
Serial.setDebugOutput(false);
}
yield();
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop(void){
server.handleClient();
}
Я сделал вот такую страничку для удобства управления своим бризером.
<html>
<head>
<script>
function sendIR(str) {
if (str.length == 0) {
// document.getElementById("txtHint").innerHTML = "";
return;
} else {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
// document.getElementById("txtHint").innerHTML = this.responseText;
}
};
xmlhttp.open("GET", "http://192.168.0.193/" + str, true);
xmlhttp.send();
}
}
</script>
</head>
<body>
<div id="demo">
<button type="button" onclick="sendIR('ir?code=16724175')">Up</button>
<button type="button" onclick="sendIR('ir?code=16711935')">Down</button>
<button type="button" onclick="sendIR('ir?code=16722135')">Set</button>
<button type="button" onclick="sendIR('ir?code=16720095')">Power</button>
<button type="button" onclick="sendIR('seq?need_wait=11000&code=16722135&count=2&delay=20');sendIR('seq?code=16711935&count=50&delay=20');sendIR('seq?code=16724175&count=21&delay=20')">day</button>
<button type="button" onclick="sendIR('seq?need_wait=11000&code=16722135&count=2&delay=20');sendIR('seq?code=16711935&count=50&delay=20');sendIR('seq?code=16724175&count=35&delay=20')">night</button>
<a href="http://192.168.0.193/update">update</a>
</div>
</body>
</html>
Конкретно в моем случае бризер работает с пультом необычно, при первом нажатии он «просыпается», а именно включает подсветку экранчика, и только после этого начинает принимать команды. При автоматизации стоит учитывать это.
Надеюсь данная инструкция кому-то пригодится. Прошу делиться доработанными прошивками.
Комментарии (21)
N0Good
16.02.2017 23:12+1играюсь с этим уже не первый день. Основная проблема в том, что для сплита пульт шлёт не тупо команды а-ля включить, выключить, температуру выше-ниже, а код состояния с уже указанной температурой и доп опциями (типа турборежим или работа направляющих). Причём для включения-выключения используется повтор последнего состояния. Да и разобрать что в отосланном коде что ощначает тоже непросто.
apple01
17.02.2017 03:28+1погуглил, окызавается продают универсальные пульты которые можно запрограммировать и даже приложения для телефона, а коды уже собраны для разных брендов, один из примеров здесь http://removeandreplace.com/2016/06/17/universal-air-conditioner-remote-control-codes/.
natan555
17.02.2017 09:28+1https://geektimes.ru/post/258064/
http://www.instructables.com/id/Reverse-engineering-of-an-Air-Conditioning-control/?ALLSTEPS
Могу поделится наполовину разобранным кодом от пульта Samsung ARH-465
mitgard
17.02.2017 09:29+1От напряжения 3.3v светодиод так-же нормально работает.
Через диод протекает некий ток, и при 3.3V очевидно он будет меньше. А значит надо смотреть какая будет интенсивность излучения на получившемся токе. Посмотрите как рассчитать диод — это не сложно.
И вообще отсутствие резистора последовательно с диодом- плохая практика.KonstantinSoloviov
17.02.2017 10:54Добавим так же, что включать диоды параллельно — не комильфо из-за крутых и нелинейных ВАХ — один всегда страдает больше другого.
Итого: либо к каждому диоду добавить по токоограничительному резистору, либо включаем диоды последовательно, но все равно с резистором.
Почему «оно и так работает» — объяснить просто:
(1) импульсный режим (диод сгореть не успевает, сколько проживет — вопрос),
(2) внутреннее сопротивление источника (которое задает предельный ток).
gibson_dev
17.02.2017 10:09+3Было бы не плохо все таки ESP сразу в бризер воткнуть. У него же есть расширение MAC позволяющее использовать MagicAir — значит все выводы по управлению уже есть (может там и uart) банальный
lingvo
17.02.2017 18:56А нет готового продукта, который выполнял бы такую функцию? Желательно бы с поддержкой протокола MQTT.
basicus
18.02.2017 09:17+1Для управления кондиционером Gree сделал похожее устройство.
Сначала тоже как Вы пытался сделать через чтение кодов пульта, но не вышло. Как оказалось там идёт две посылки, и они не являются повтором одного и того же кода (это я узнал уже позже). Да и этот метод не подходит для кондиционеров, там надо управлять параметрами. Недостаточно записать несколько состояний.
Также у меня стояла задача интегрировать управление кондиционером в умный дом wirenboard. Это требует поддержки mqtt.
В результате удалось всё реализовать: кондиционер полностью интегрирован в интерфейс управления умным домом, я могу управлять температурой, скоростью, режимом. Всё стабильно работает с декабря на даче. Так как основное отопление дачи кондиционер стало удобно: уезжаем — температура 20, вечером за день до приезда — включаю на 27. Дом прогревается. Управляю в основном с мобильного, через сайт.
Для решения задачи использовал как и Вы ESP-01, но к ножкам чипа не подключался. Я использовал уже выведенные пины. Для решения проблемы с запуском после включения подбирал резисторы подтягивающие. Ещё были сложности с подбором резисторов цепи IR чтобы можно было управлять кондиционером хотя бы с метров 2-3, так как возможности повесить ESP прямо на кондиционер нет.
Что касается управления кондиционером, то нашёл таки на гитхаб код под Gree, использовал его. Еще позже нашёл библиотеку с поддержкой большего количества производителей кондиционеров. Так же использовал библиотеку mqtt для соединения в wirenboard. В mqtt умного дома создал необходимые топики. Esp при подключении подписывается на них и соответственно выставляет режим.
Чтобы все контролы объединить в интерфейсе, пришлось модифицировать код Homeui wirenboard. Для этого пришлось немного изучить angular.
Изначально хотел написать статью и выложить код на github, но нехватает времени.
LexB
18.02.2017 09:32Спасибо за развернутый комментарий.
но к ножкам чипа не подключался. Я использовал уже выведенные пины. Для решения проблемы с запуском после включения подбирал резисторы подтягивающие
К слову полезное замечание. Почему-то по подключению светодиодов много комментариев, а об этой проблеме никто не упомянул.
Изначально хотел написать статью и выложить код на github, но нехватает времени.
Все-же надеюсь что время найдется.
SolarW
19.02.2017 05:34-1Интересно было бы увидеть ссылку на библиотеку с поддержкой большого количества кондиционеров.
boingo-00
Китайский свисток на PL2303 покатит? FT232 в основном либо дорого, либо подделка
e_butcher
Можно и ардуину использовать, если есть. Для этого на ней надо замкнуть RST на GND, а ESP подключить следующим образом: RX->RX, TX->TX. Несмотря на различные напряжения логических уровней (5В у ардуино и 3,3В у ESP) на практике все прекрасно работает.