Нашел способ подружить кондиционер (или другой прибор управляемым пультом дистанционного управления) и умный дом, либо сделать управление этим устройством, например с сотового.
В теории просто, подключаем 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 у меня получились такие кода:
Фотоприемник больше не нужен, пока не потребуется «сграбить» кода другого пульта.
* Подключаем ИК светодиод по схеме.
(Картинка заимствована у Fritzing)
GPIO можно использовать другой. От напряжения 3.3v светодиод так-же нормально работает.
UPD: Как справедливо заметили в комментариях желательно использовать токоограничивающий резистор.
* Демо прошивка с сервером находится тут
\IRremoteESP8266\examples\IRServer\IRServer.ino
* Меняем в ней название и пароль вашей точки доступа, чтобы esp мог подключиться к ней. А так-же номер используемого GPIO
* Прошиваем модуль.
* При подключении в консоль будет выведен IP адрес выделенный esp.
Теперь можно отправлять кода вводя в броузере адрес вида 192.168.1.1/ir?code=16720095 (просто подставьте нужный IP и код).
Я сделал вот такую страничку для удобства управления своим бризером.
Конкретно в моем случае бризер работает с пультом необычно, при первом нажатии он «просыпается», а именно включает подсветку экранчика, и только после этого начинает принимать команды. При автоматизации стоит учитывать это.
Надеюсь данная инструкция кому-то пригодится. Прошу делиться доработанными прошивками.
В теории просто, подключаем 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();
}
Я сделал вот такую страничку для удобства управления своим бризером.
brizer.html
<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>
Конкретно в моем случае бризер работает с пультом необычно, при первом нажатии он «просыпается», а именно включает подсветку экранчика, и только после этого начинает принимать команды. При автоматизации стоит учитывать это.
Надеюсь данная инструкция кому-то пригодится. Прошу делиться доработанными прошивками.