Пришло лето, а следом и жара. Температура растет, а вместе с ней и желание включить кондиционер. Нет ничего проще, чем нажать кнопку на пульте и выставить комфортную температуру.
В более продвинутых версиях сплит-систем имеются модули WiFi при помощи которых можно удаленно управлять кондиционером через смартфон. Но что делать, если у нас бюджетный кондиционер? Как управлять им через Интернет?
В этой статье мы рассмотрим, как с помощью современных технологий, а главное за «копейки» научить наш бюджетный кондиционер работать через Интернет. Все просто — DIY: покупаем у китайцев микроконтроллер ESP8266 NodeMcu (160 рублей), ИК-приемник/передатчик (70 рублей), заливаем прошивку, устанавливаем приложение на Android.
Пульт от кондиционера включает в себя инфракрасный передатчик — ИК светодиод, через который передается сигнал на ИК приемник. Каждая кнопка пульта передает уникальный сигнал — последовательность импульсов. В нашем проекте мы будем считывать сигнал с пульта и повторять его через приложение на Android, тем самым управляя кондиционером.
Управление будет происходить на примере самой бюджетной сплит-системы DEXP AC-R07OMA/W.
Перехватывать сигнал будем при помощи контроллера и ИК-приемника.
Контроллер можно использовать любой, будь то ESP или arduino. В моем случае использовалась Arduino Nano.
Собираем на макетной плате по следующей схеме (data в D2):
Фото вдогонку:
Заливаем на ардуину следующий скетч:
// Выход ИК приемника подкючаем к пину D2 #define LEDPIN 13 // Индикатор приема - зажигаем светодиод #define maxLen 800 //Длина приемного буфера,можно увеличить это значение для Arduino с более чем 2k SRAM volatile unsigned int irBuffer[maxLen]; //Буфер хранения данных (времени срабатывания прерываний) volatile unsigned int x = 0; void setup() { Serial.begin(9600); attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//Настройка прерывания для приема ИК-сигнала } void loop() { Serial.println(F("Ожидаем нажатия кнопки на пульте")); delay(5000); // Пауза 5 сек if (x) { // если сигнал захвачен digitalWrite(LEDPIN, HIGH);// Зажечь индикатор приема сигнала Serial.println(); Serial.print(F("Raw: (")); // Заголовок raw дампа Serial.print((x - 1)); Serial.print(F(") ")); detachInterrupt(0); for (int i = 1; i < x; i++) { if (!(i & 0x1)) Serial.print(F("")); Serial.print(irBuffer[i] - irBuffer[i - 1]); Serial.print(F(",")); } Serial.println(); for (int n = 3; n < x; n++) { if (!(n & 0x1)) { if ( (irBuffer[n] - irBuffer[n - 1]) > 1000 ) { Serial.print("1"); } else { Serial.print("0"); } if ( ((n -2) % 8 ) == 0 ) { Serial.print(" "); } } } x = 0; Serial.println(); Serial.println(); digitalWrite(LEDPIN, LOW);//Выключение индикатора приема attachInterrupt(0, rxIR_Interrupt_Handler, CHANGE);//Переназначить прерывание для приема ИК-сигнала } } void rxIR_Interrupt_Handler() { if (x > maxLen) return; // игнорировать, если irBuffer уже заполнен irBuffer[x++] = micros(); // Запись времени изменения сигнала }
Далее открываем монитор порта в Arduino IDE, подносим пульт от кондиционера к ИК-приемнику, нажимаем кнопку, которой хотим управлять дистанционной, смотрим перехваченный сигнал кнопки в строке «Raw»:
Запоминаем все считанные сигналы и переходим к следующему шагу.
Для передачи сигнала на кондиционер нам понадобится плата esp8266 nodemcu v3 (можно использовать другие версии esp8266) с WiFi модулем на борту и ИК-светодиод.
Для удобства и при наличии 3d-принтера можно распечатать корпус для платы:
ИК-светодиод паяем длинной ногой к пин D2, короткой к GND:
Скачиваем приложение на свой смартфон «Blynk». Регистрируемся в приложении, указав свой E-mail адрес. После регистрации, в настройках приложения отправляем на свой почтовый адрес токен/ключ (в разделе «Create New Project» — «AUTH TOKEN»). Токен нам понадобится далее в скетче. Для создания проекта нажимаем в приложении кнопку «Create», затем в новом окне в верхней части экрана кликаем по кнопке «Добавить» (круглая кнопка с плюсом). В меню «Widget Box» выбираем «Button».
Добавляем четыре кнопки, как указано на скриншоте:
Отредактировав виртуальные кнопки, кликаем по кнопке «Пуск» (кнопка в виде треугольника). Все, наше приложение готово:
Для того, чтобы наше приложение начало работать, необходимо залить скетч на контроллер ESP8266.
Вставляем в скетч вместо «ХХХ....», отправленный ранее на почту токен, а также логин и пароль от домашней WiFi сети.
В переменных «buttonON», «buttonOFF», «button24», «button20», «button18» вставляем сигналы, полученные в первом шаге статьи с кнопок пульта. Не забываем указывать длину (например buttonON[199]). Думаю, здесь все понятно.
#define BLYNK_PRINT Serial #include <ESP8266WiFi.h> #include <BlynkSimpleEsp8266.h> char auth[] = "XXXXXX"; // WiFi настройки char ssid[] = "XXXXXX"; // Название сети char pass[] = "XXXXXX"; // Пароль #include <Arduino.h> #include <IRremoteESP8266.h> #include <IRsend.h> const uint16_t kIrLed = 4; // ESP8266 GPIO. Пин по умолчанию: 4 (D2). IRsend irsend(kIrLed); uint16_t buttonON[199] = {4388,4428,552,1632,548,524,572,1640,576,1608,548,544,548,548,548,1636,552,544,552,544,576,1612,548,548,552,544,548,1636,576,1608,548,544,552,1640,548,548,548,548,548,520,576,1632,548,1612,572,1636,548,1636,544,1616,548,1664,548,1636,548,1636,520,572,524,576,520,572,500,596,548,548,552,548,520,1668,520,576,520,572,524,1660,496,600,520,576,520,576,524,1660,524,572,548,1640,520,1664,520,572,496,1696,496,1684,524,1660,524,5272,4336,4460,496,1684,496,580,492,1716,496,1688,496,600,496,576,544,1636,548,576,544,552,548,1640,520,572,552,544,496,1688,520,1660,524,572,524,1664,524,576,496,600,544,548,500,1684,524,1660,520,1660,496,1664,572,1636,496,1692,524,1660,548,1632,496,600,500,596,524,572,472,624,496,600,496,600,472,1716,524,572,496,596,524,1660,472,624,496,600,496,600,496,1688,472,624,524,1664,496,1684,524,572,472,1716,472,1712,520,1664,520}; uint16_t buttonOFF[199] = {4412,4388,548,1660,496,596,500,1664,524,1656,500,596,524,596,496,1660,524,600,524,548,496,1712,528,568,500,572,524,1684,500,1656,524,572,552,1660,500,596,476,1708,500,1684,472,1712,500,1680,504,568,500,1688,552,1632,576,1640,552,540,528,568,552,544,528,568,524,1632,552,544,576,548,552,1636,552,1604,528,1660,520,596,528,568,528,544,548,544,552,572,500,596,500,572,528,592,500,1688,524,1636,524,1656,552,1656,500,1660,496,5296,4384,4412,496,1712,472,624,496,1688,500,1684,500,572,524,596,500,1680,476,624,552,520,552,1660,552,520,548,568,504,1680,500,1684,472,624,500,1664,524,596,500,1684,500,1684,500,1656,524,1684,524,572,500,1684,504,1680,504,1684,552,520,552,544,496,624,472,624,500,1680,500,596,528,572,496,1668,552,1652,552,1608,548,572,524,544,552,568,528,544,524,596,500,600,524,544,528,592,500,1664,520,1684,500,1660,524,1684,496,1688,472}; uint16_t button24[199] = {4360,4436,476,1684,576,544,500,1664,524,1680,476,624,496,572,528,1680,500,572,552,572,500,1688,552,520,572,520,528,1656,576,1632,524,544,528,1688,500,596,500,596,528,544,576,1632,524,1656,504,1680,528,1656,500,1684,528,1664,524,1632,576,1632,524,572,528,544,548,544,528,596,496,600,524,572,500,1688,528,568,524,568,528,1632,576,520,576,520,524,596,528,1660,500,592,500,1688,528,1632,576,516,552,1636,524,1660,552,1632,496,5324,4360,4412,496,1712,472,620,472,1692,496,1688,496,596,528,592,476,1708,504,596,524,572,500,1688,500,596,500,568,528,1684,496,1684,524,544,500,1692,528,592,504,592,500,596,500,1684,524,1656,528,1656,552,1608,548,1660,500,1664,496,1712,552,1628,528,568,500,596,524,572,500,592,504,596,500,596,528,1660,500,596,500,592,504,1680,500,596,524,548,548,572,528,1656,476,620,500,1664,496,1708,552,520,496,1716,500,1684,552,1632,476}; uint16_t button20[199] = {4360,4468,500,1684,472,600,520,1664,500,1708,472,624,472,624,520,1640,496,624,524,548,500,1712,496,600,520,572,476,1684,500,1708,472,600,496,1692,496,600,496,600,496,600,496,1688,496,1600,580,1712,472,1688,496,1688,496,1688,500,1684,548,1660,496,576,520,576,496,596,548,548,548,552,496,600,496,596,500,1688,496,596,500,1688,572,520,500,600,544,552,572,1640,472,1684,520,576,544,1640,524,572,496,1692,544,1660,472,1688,548,5244,4360,4432,500,1684,524,568,528,1664,548,1632,524,572,500,596,500,1680,528,572,524,572,524,1664,500,596,524,572,524,1656,524,1660,524,568,528,1664,524,572,500,596,524,568,528,1656,524,1660,500,1684,524,1656,524,1664,524,1660,528,1656,524,1660,524,572,524,572,524,572,524,568,524,572,528,568,528,572,524,1660,524,572,524,1660,524,572,524,572,524,572,528,1656,528,1656,528,568,524,1664,524,568,528,1660,524,1660,524,1660,524}; uint16_t button18[199] = {4364,4436,500,1684,472,624,524,1660,528,1628,528,596,500,596,496,1684,528,572,500,596,500,1688,496,600,500,592,552,1632,500,1684,496,596,528,1660,528,572,524,572,500,592,528,1632,548,1632,552,1632,524,1684,496,1664,576,1636,472,1688,520,1684,528,568,500,596,524,572,500,568,524,600,496,600,500,596,500,596,524,1664,496,1684,472,624,500,572,524,572,524,1684,524,1656,500,1684,500,596,524,572,548,1632,524,1660,552,1628,500,5272,4384,4384,496,1712,500,592,528,1660,528,1656,548,544,552,544,552,1632,552,544,528,568,552,1612,548,572,552,540,528,1656,552,1632,552,544,552,1636,552,548,552,516,524,596,552,1632,528,1652,556,1604,576,1632,552,1632,552,1636,576,1580,552,1656,552,544,552,544,552,520,524,592,500,600,500,596,552,520,524,596,548,1636,552,1632,552,544,552,544,552,544,552,1612,520,1684,552,1632,548,520,580,516,576,1632,552,1628,528,1656,504}; void setup() { irsend.begin(); Serial.begin(115200); Blynk.begin(auth, ssid, pass); } void loop() { Blynk.run(); } // Переключатель ВКЛ/ВЫКЛ BLYNK_WRITE(V1) { int value = param.asInt(); // Получить значение как целое число Serial.println(value); if(value == 0){ irsend.sendRaw(buttonON, 199, 38); Serial.println("Включение кондиционера"); }else if(value == 1){ irsend.sendRaw(buttonOFF, 199, 38); Serial.println("Выключение кондиционера"); } } // 24 градуса BLYNK_WRITE(V2) { int value = param.asInt(); // Получить значение как целое число Serial.println(value); if(value == 0){ irsend.sendRaw(button24, 199, 38); Serial.println("24 градуса"); } } // 20 градусов BLYNK_WRITE(V3) { int value = param.asInt(); // Получить значение как целое число Serial.println(value); if(value == 0){ irsend.sendRaw(button20, 199, 38); Serial.println("20 градусов"); } } // 18 градусов BLYNK_WRITE(V4) { int value = param.asInt(); // Получить значение как целое число Serial.println(value); if(value == 0){ irsend.sendRaw(button18, 199, 38); Serial.println("18 градусов"); } }
Скетч залит. Вот такое устройство у нас получилось, по цене примерно 230 рублей. Подключаем к зарядке 5v, например телефонной, направляем в сторону кондиционера.
Теперь у нас все должно работать. Заходим в приложение Blynk на смартфоне, клацаем по кнопке «Вкл» и вауля, кондиционер включается без родного ДУ!
Вариант без Blynk:
#include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <IRremoteESP8266.h> #include <IRsend.h> const char* ssid = "XXXXX"; // Название Wi-Fi сети const char* password = "XXXXX"; // Парольот Wi-Fi ESP8266WebServer server(80); IRsend irsend(4); // ИК-светодиод подключен к D2 (GPIO4) uint16_t buttonON[199] = {4388,4428,552,1632,548,524,572,1640,576,1608,548,544,548,548,548,1636,552,544,552,544,576,1612,548,548,552,544,548,1636,576,1608,548,544,552,1640,548,548,548,548,548,520,576,1632,548,1612,572,1636,548,1636,544,1616,548,1664,548,1636,548,1636,520,572,524,576,520,572,500,596,548,548,552,548,520,1668,520,576,520,572,524,1660,496,600,520,576,520,576,524,1660,524,572,548,1640,520,1664,520,572,496,1696,496,1684,524,1660,524,5272,4336,4460,496,1684,496,580,492,1716,496,1688,496,600,496,576,544,1636,548,576,544,552,548,1640,520,572,552,544,496,1688,520,1660,524,572,524,1664,524,576,496,600,544,548,500,1684,524,1660,520,1660,496,1664,572,1636,496,1692,524,1660,548,1632,496,600,500,596,524,572,472,624,496,600,496,600,472,1716,524,572,496,596,524,1660,472,624,496,600,496,600,496,1688,472,624,524,1664,496,1684,524,572,472,1716,472,1712,520,1664,520}; uint16_t buttonOFF[199] = {4412,4388,548,1660,496,596,500,1664,524,1656,500,596,524,596,496,1660,524,600,524,548,496,1712,528,568,500,572,524,1684,500,1656,524,572,552,1660,500,596,476,1708,500,1684,472,1712,500,1680,504,568,500,1688,552,1632,576,1640,552,540,528,568,552,544,528,568,524,1632,552,544,576,548,552,1636,552,1604,528,1660,520,596,528,568,528,544,548,544,552,572,500,596,500,572,528,592,500,1688,524,1636,524,1656,552,1656,500,1660,496,5296,4384,4412,496,1712,472,624,496,1688,500,1684,500,572,524,596,500,1680,476,624,552,520,552,1660,552,520,548,568,504,1680,500,1684,472,624,500,1664,524,596,500,1684,500,1684,500,1656,524,1684,524,572,500,1684,504,1680,504,1684,552,520,552,544,496,624,472,624,500,1680,500,596,528,572,496,1668,552,1652,552,1608,548,572,524,544,552,568,528,544,524,596,500,600,524,544,528,592,500,1664,520,1684,500,1660,524,1684,496,1688,472}; uint16_t button24[199] = {4360,4436,476,1684,576,544,500,1664,524,1680,476,624,496,572,528,1680,500,572,552,572,500,1688,552,520,572,520,528,1656,576,1632,524,544,528,1688,500,596,500,596,528,544,576,1632,524,1656,504,1680,528,1656,500,1684,528,1664,524,1632,576,1632,524,572,528,544,548,544,528,596,496,600,524,572,500,1688,528,568,524,568,528,1632,576,520,576,520,524,596,528,1660,500,592,500,1688,528,1632,576,516,552,1636,524,1660,552,1632,496,5324,4360,4412,496,1712,472,620,472,1692,496,1688,496,596,528,592,476,1708,504,596,524,572,500,1688,500,596,500,568,528,1684,496,1684,524,544,500,1692,528,592,504,592,500,596,500,1684,524,1656,528,1656,552,1608,548,1660,500,1664,496,1712,552,1628,528,568,500,596,524,572,500,592,504,596,500,596,528,1660,500,596,500,592,504,1680,500,596,524,548,548,572,528,1656,476,620,500,1664,496,1708,552,520,496,1716,500,1684,552,1632,476}; uint16_t button20[199] = {4360,4468,500,1684,472,600,520,1664,500,1708,472,624,472,624,520,1640,496,624,524,548,500,1712,496,600,520,572,476,1684,500,1708,472,600,496,1692,496,600,496,600,496,600,496,1688,496,1600,580,1712,472,1688,496,1688,496,1688,500,1684,548,1660,496,576,520,576,496,596,548,548,548,552,496,600,496,596,500,1688,496,596,500,1688,572,520,500,600,544,552,572,1640,472,1684,520,576,544,1640,524,572,496,1692,544,1660,472,1688,548,5244,4360,4432,500,1684,524,568,528,1664,548,1632,524,572,500,596,500,1680,528,572,524,572,524,1664,500,596,524,572,524,1656,524,1660,524,568,528,1664,524,572,500,596,524,568,528,1656,524,1660,500,1684,524,1656,524,1664,524,1660,528,1656,524,1660,524,572,524,572,524,572,524,568,524,572,528,568,528,572,524,1660,524,572,524,1660,524,572,524,572,524,572,528,1656,528,1656,528,568,524,1664,524,568,528,1660,524,1660,524,1660,524}; uint16_t button18[199] = {4364,4436,500,1684,472,624,524,1660,528,1628,528,596,500,596,496,1684,528,572,500,596,500,1688,496,600,500,592,552,1632,500,1684,496,596,528,1660,528,572,524,572,500,592,528,1632,548,1632,552,1632,524,1684,496,1664,576,1636,472,1688,520,1684,528,568,500,596,524,572,500,568,524,600,496,600,500,596,500,596,524,1664,496,1684,472,624,500,572,524,572,524,1684,524,1656,500,1684,500,596,524,572,548,1632,524,1660,552,1628,500,5272,4384,4384,496,1712,500,592,528,1660,528,1656,548,544,552,544,552,1632,552,544,528,568,552,1612,548,572,552,540,528,1656,552,1632,552,544,552,1636,552,548,552,516,524,596,552,1632,528,1652,556,1604,576,1632,552,1632,552,1636,576,1580,552,1656,552,544,552,544,552,520,524,592,500,600,500,596,552,520,524,596,548,1636,552,1632,552,544,552,544,552,544,552,1612,520,1684,552,1632,548,520,580,516,576,1632,552,1628,528,1656,504}; void handleRoot() { String html = R"=====( <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Управление кондиционером</title> <style> body { font-family: Arial, sans-serif; text-align: center; margin: 0; padding: 20px; } .btn { background-color: #4CAF50; border: none; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 10px 5px; cursor: pointer; border-radius: 8px; width: 200px; } .btn-off { background-color: #f44336; } .btn-temp { background-color: #2196F3; } .status { margin: 20px; font-size: 18px; } </style> </head> <body> <h1>Управление кондиционером</h1> <div> <button class="btn" onclick="sendCommand('on')">Включить</button> <button class="btn btn-off" onclick="sendCommand('off')">Выключить</button> </div> <div> <button class="btn btn-temp" onclick="sendCommand('24')">24°C</button> <button class="btn btn-temp" onclick="sendCommand('20')">20°C</button> <button class="btn btn-temp" onclick="sendCommand('18')">18°C</button> </div> <div class="status" id="status">Готов к работе</div> <script> function sendCommand(cmd) { document.getElementById('status').innerText = 'Отправка команды...'; fetch('/control?cmd=' + cmd) .then(response => response.text()) .then(data => { document.getElementById('status').innerText = 'Команда выполнена: ' + data; }) .catch(error => { document.getElementById('status').innerText = 'Ошибка: ' + error; }); } </script> </body> </html> )====="; server.send(200, "text/html", html); } void handleControl() { if (server.hasArg("cmd")) { String command = server.arg("cmd"); String response = ""; if (command == "on") { irsend.sendRaw(buttonON, 199, 38); response = "Кондиционер включен"; } else if (command == "off") { irsend.sendRaw(buttonOFF, 199, 38); response = "Кондиционер выключен"; } else if (command == "24") { irsend.sendRaw(button24, 199, 38); response = "Установлена температура 24°C"; } else if (command == "20") { irsend.sendRaw(button20, 199, 38); response = "Установлена температура 20°C"; } else if (command == "18") { irsend.sendRaw(button18, 199, 38); response = "Установлена температура 18°C"; } else { response = "Неизвестная команда"; } server.send(200, "text/plain", response); Serial.println("Command: " + command + " - " + response); } else { server.send(400, "text/plain", "Не указана команда"); } } void setup() { Serial.begin(115200); irsend.begin(); // Подключаемся к WiFi WiFi.begin(ssid, password); Serial.println("Подключение к WiFi..."); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi подключен"); Serial.println("IP адрес: "); Serial.println(WiFi.localIP()); // Настраиваем обработчики запросов server.on("/", handleRoot); server.on("/control", handleControl); server.begin(); Serial.println("HTTP сервер запущен"); } void loop() { server.handleClient(); }
Далее узнаем на роутере IP подключенного ESP8266, вставляем IP в браузер и управляем.
1. Плата ESP8266 nodemcu v3 CP2102 serial port
https://aliexpress.ru/item/4000550036826.html
2. ИК-приемник/передатчик HX1838
https://aliexpress.ru/catalog/komplekt-distantsionnogo-upravlenija.html
3. Arduino Nano v3 Atmega328
https://aliexpress.ru/item/4000587268145.html
4. Макетная плата MB102
https://aliexpress.ru/item/850064380.html
5. 3d-модель бокса для платы ESP8266