ESP8266:Примеры/Управление RGB-лампочкой с помощью ИК-передатчика и ESP8266

Материал из Онлайн справочника
Перейти к навигации Перейти к поиску

Перевод: Максим Кузьмин (Cubewriter) Контакты:</br>* Skype: cubewriter</br>* E-mail: cubewriter@gmail.com</br>* Максим Кузьмин на freelance.ru
Проверка/Оформление/Редактирование: Мякишев Е.А.


Pixel Art Mini Meow Animated.gif Черновик


Управление RGB-лампочкой с помощью ИК-передатчика и ESP8266

В этом проекте мы научимся использовать ИК-передатчик для управления RGB-светодиодной ИК-лампочкой при помощи веб-сервера на базе ESP8266. Мы сможем отправлять команды для включения/выключения лампочки, уменьшения/увеличения ее яркости, переключения ее на красный, зеленый, синий, фиолетовый цвета и т.д. Проект будет поделен на 2 части:

  1. Расшифровка ИК-сигналов, отправляемых пультом управления лампочкой
  2. Настройка ESP8266 на отправление этих ИК-сигналов

Передача и прием ИК-сигналов

На фото ниже изображен ИК-приемник TSOP4838.

TSOP4838 pinout 1.jpg

Как видите, он оснащен 3 контактами:

  • OUT (вывод данных);
  • GND (Заземление);
  • VCC (Источник напряжения);

Когда вы нажимаете на кнопки на пульте управления, он отправляет модулированные ИК-сигналы. Они содержат информацию, принимаемую ИК-приемником.

IR emitter.png

Каждая кнопка отправляет собственный ИК-сигнал. Таким образом, мы можем привязать каждый из этих ИК-сигналов к кнопкам на веб-странице, обслуживаемой ESP8266. Затем эти сигналы – отправляемые ИК-передатчиком, подключенным к ESP8266 – можно будет использовать для управления лампочкой.

Необходимое оборудование

Часть 1 – Расшифровка ИК-сигналов

В этой части проекта мы расшифруем ИК-сигналы, привязанные к каждой кнопке, чтобы потом эмулировать их при помощи ESP8266.

Схема

Подключите ИК-приемник и ESP8266 друг к другу согласно схеме ниже.

Esp8266 tsop connect 1.png
Pixel Art Mini Meow Animated.gif Данная схема приведена для ИК приемника TSOP4838, другие модели могут иметь различную распиновку.


Код

Для работы с ИК-передатчиком и ИК-приемником нам нужно будет установить в IDE Arduino библиотеку «IRremoteESP8266». Для этого кликните в IDE Arduino на «Скетч» > «Подключить библиотеку» > «Управлять библиотеками...» (Sketch > Include Library > Manage Libraries…).

Затем вбейте в поиске «ir remote esp8266» и, найдя нужную библиотеку, кликните по кнопке «Установка» (Install). Или можете загрузить ее ZIP-архив отсюда и установить вручную.

Скопируйте код ниже в IDE Arduino, а затем загрузите его на ESP8266. Перед этим проверьте, правильные ли в IDE Arduino выбраны плата и COM-порт.

 1 /*
 2  * https://github.com/markszabo/IRremoteESP8266/blob/master/examples/IRrecvDemo/IRrecvDemo.ino
 3  *
 4  * IRremoteESP8266: IRrecvDemo 
 5  *
 6  * Демонстрирует получение ИК-кодов при помощи библиотеки «IRrecv».
 7  * Ко входному контакту RECV_PIN 
 8  * должен быть подключен ИК-детектор/демодулятор.
 9  * Авторские права принадлежат Кену Ширриффу (2009), http://arcfn.com
10  * Изменения:
11  *   Версия 0.2, июнь 2017
12  *    - Изменен GPIO-контакт
13         (теперь он такой же, как и в других примерах);
14  *    - Для печати «uint64_t» используется наш собственный метод;
15  *    - Скорость передачи данных изменена на 115200 бод.
16  *   Версия 0.1, сентябрь 2015
17  *    - Основана на скетче «IrsendDemo» (версия 0.1, июль 2009), 
18  *      написанном Кеном Ширриффом
19  */
20 
21 #ifndef UNIT_TEST
22 #include <Arduino.h>
23 #endif
24 #include <IRremoteESP8266.h>
25 #include <IRrecv.h>
26 #include <IRutils.h>
27 
28 // ИК-детектор/демодулятор подключен к контакту GPIO14
29 // (на плате NodeMCU это контакт D5):
30 uint16_t RECV_PIN = 14;
31 
32 IRrecv irrecv(RECV_PIN);
33 
34 decode_results results;
35 
36 void setup() {
37   Serial.begin(115200);
38   irrecv.enableIRIn();  // запускаем приемник
39 }
40 
41 void loop() {
42   if (irrecv.decode(&results)) {
43     // print() и println() не умеют 
44     // обрабатывать печать вместительных типов данных  (uint64_t):
45     serialPrintUint64(results.value, HEX);
46     Serial.println("");
47     irrecv.resume();  // получаем следующее значение
48   }
49   delay(100);
50 }

Открываем монитор порта на скорости 115200 бод.

В этом проекте мы будем эмулировать 10 кнопок пульта управления. Нажмите на пульте на кнопку «ON». В результате в мониторе порта должен появиться код для этой кнопки.

Примечание: На одну и ту же кнопку можно нажать несколько раз – чтобы убедиться, что код получен именно для той кнопки, что вам нужна. Если вы увидите что-то вроде «FFFFFFFF», просто игнорируйте, это мусор.

Esp8266 tsop ir reciever serial monitor 1.PNG

Повторите этот процесс и для других кнопок. Запишите коды для всех кнопок, т.к. позже они нам еще понадобятся. На картинке ниже показаны ИК-сигналы для всех нужных нам кнопок на пульте управления.

Remote buttons codes 1.png

Часть 2 – Настройка ESP8266 на отправку ИК-сигналов

В этой части мы построим цепь из светодиодного ИК-передатчика, управляемого с помощью веб-сервера на базе ESP8266.

Схема

Подключите ИК-передатчик к ESP8266 согласно схеме ниже.

Esp8266 ir led 1.png

ИК-передатчик нужно поместить рядом с лампочкой, чтобы она могла принимать отправляемые им ИК-сигналы.

Код

Код ниже запустит на вашей ESP8266 веб-сервер, передающий данные через порт «80». Веб-сервер будет показывать в браузере простую веб-страницу с 10 кнопками, управляющими RGB-светодиодной лампочкой.

Скопируйте код ниже в IDE Arduino, но пока не загружайте.

Сначала прочтите следующий раздел, в котором рассказывается, как отредактировать этот скетч, чтобы он заработал на вашей ESP8266.

Pixel Art Mini Meow Animated.gif Если у вас код ниже работает нестабильно, то вы можете попробовать вот этот альтернативный вариант.


  1 /*
  2  * Скетч для управления RGB-светодиодной ИК-лампочкой с помощью ESP8266 
  3  * Руи Сантос 
  4  * Более подробно о проекте на: http://randomnerdtutorials.com
  5  */
  6 
  7 #include <ESP8266WiFi.h>
  8 
  9 #ifndef UNIT_TEST
 10 #include <Arduino.h>
 11 #endif
 12 #include <IRremoteESP8266.h>
 13 #include <IRsend.h>
 14 
 15 // ИК-передатчик управляется через контакт GPIO4 (D2):
 16 IRsend irsend(4);  
 17 
 18 // Вставьте здесь SSID и пароль для своей WiFi-сети:
 19 const char* ssid = "REPLACE_WITH_YOUR_SSID";
 20 const char* password = "REPLACE_WITH_YOUR_PASSWORD";
 21 
 22 // Переменная для хранения информации о том,
 23 // какая кнопка была последней нажата на веб-странице:
 24 String lastState;
 25 
 26 // Создаем объект для сервера с портом «80»:
 27 WiFiServer server(80);
 28 
 29 void setup() {
 30   irsend.begin();
 31   
 32   Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
 33   delay(10);
 34 
 35   // Подготавливаем контакт GPIO4:
 36   pinMode(4, OUTPUT);
 37   digitalWrite(4, 0);
 38   
 39   // Подключаемся к WiFi-сети:
 40   Serial.print("Connecting to ");  //  "Подключаемся к "
 41   Serial.println(ssid);
 42   
 43   WiFi.begin(ssid, password);
 44   
 45   while (WiFi.status() != WL_CONNECTED) {
 46     delay(500);
 47     Serial.print(".");
 48   }
 49   Serial.println("WiFi connected");  //  "Подключились к WiFi"
 50   
 51   // Запускаем сервер:
 52   server.begin();
 53   Serial.println("Server started");  //  "Сервер запущен"
 54 
 55   // Печатаем IP-адрес:
 56   Serial.println(WiFi.localIP());
 57 }
 58 
 59 void loop() {
 60   // Проверяем, подключился ли клиент:
 61   WiFiClient client = server.available();
 62   if (!client) {
 63     return;
 64   }
 65   
 66   // Ждем, пока клиент отправит какие-нибудь данные:
 67   Serial.println("new client");  //  "новый клиент"
 68   while(!client.available()){
 69     delay(1);
 70   }
 71   
 72   // Считываем первую строчку запроса:
 73   String req = client.readStringUntil('\r');
 74   Serial.println(req);
 75   client.flush();
 76   
 77   // Смотрим, какой именно запрос отправлен:
 78   int irCode;
 79   if (req.indexOf("/lamp/on") != -1) {
 80     irCode = 0xFFE01F;
 81     lastState = "on";
 82   }
 83   else if (req.indexOf("/lamp/off") != -1) {
 84     irCode = 0xFF609F;
 85     lastState = "off";
 86   }
 87   else if (req.indexOf("/lamp/brighten") != -1) {
 88     irCode = 0xFFA05F;
 89     lastState = "brighten";
 90   }
 91   else if (req.indexOf("/lamp/dim") != -1) {
 92     irCode = 0xFF20DF;
 93     lastState = "dim";
 94   }
 95   else if (req.indexOf("/lamp/red") != -1) {
 96     irCode = 0xFF906F;
 97     lastState = "red";
 98   }
 99   else if (req.indexOf("/lamp/green") != -1) {
100     irCode = 0xFF10EF;
101     lastState = "green";
102   }
103   else if (req.indexOf("/lamp/blue") != -1) {
104     irCode = 0xFF50AF;
105     lastState = "blue";
106   }
107   else if (req.indexOf("/lamp/yellow") != -1) {
108     irCode = 0xFF8877;
109     lastState = "yellow";
110   }
111   else if (req.indexOf("/lamp/cyan") != -1) {
112     irCode = 0xFF708F;
113     lastState = "cyan";
114   }
115   else if (req.indexOf("/lamp/purple") != -1) {
116     irCode = 0xFF6897;
117     lastState = "purple";
118   }
119   else {
120     lastState = "none";
121     Serial.println("Invalid request - IR signal not sent");
122                //  "Неправильный запрос – ИК-сигнал не отправлен"
123   }
124   // Отправляем ИК-сигнал RGB-светодиодной лампочке:
125   Serial.print("NEC: ");
126   Serial.println(irCode, HEX);
127   irsend.sendNEC(irCode, 32);
128   client.flush();
129 
130   // Готовим ответ клиенту (содержит веб-страницу):
131   String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>";
132   s += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head>";  
133   s += "<h1>RGB Lamp</h1>Last state: ";
134   s += lastState;
135   s += "<p><a href=\"/lamp/on\"><button>ON</button></a><a href=\"/lamp/off\"><button>OFF</button></a></p>";
136   s += "<p><a href=\"/lamp/brighten\"><button>BRIGHTEN</button></a><a href=\"/lamp/dim\"><button>DIM</button></a></p>";
137   s += "<p><a href=\"/lamp/red\"><button>RED</button></a><a href=\"/lamp/green\"><button>GREEN</button></a><a href=\"/lamp/blue\"><button>BLUE</button></a></p>";
138   s += "<p><a href=\"/lamp/yellow\"><button>YELLOW</button></a><a href=\"/lamp/cyan\"><button>CYAN</button></a><a href=\"/lamp/purple\"><button>PURPLE</button></a></p>";
139   s += "</html>\n";
140 
141   // Отправляем ответ клиенту и отключаем его:
142   client.print(s);
143   delay(1);
144   Serial.println("Client disconnected");  //  "Клиент отключен"
145   client.stop();
146 }

Редактируем скетч

Перед загрузкой скетча в него нужно вписать SSID и пароль для своей WiFi-сети:

1 // Вставьте здесь SSID и пароль для вашей WiFi-сети:
2 const char* ssid = "REPLACE_WITH_YOUR_SSID";
3 const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Теперь возьмите ИК-коды, найденные в части 1, и впишите их в переменные «irCode», соответствующие нужным командам.

 1 // Смотрим, какой именно запрос отправлен:
 2   int irCode;
 3   if (req.indexOf("/lamp/on") != -1) {
 4     irCode = 0xFFE01F;
 5     lastState = "on";
 6   }
 7   else if (req.indexOf("/lamp/off") != -1) {
 8     irCode = 0xFF609F;
 9     lastState = "off";
10   }
11   else if (req.indexOf("/lamp/brighten") != -1) {
12     irCode = 0xFFA05F;
13     lastState = "brighten";
14   }
15   else if (req.indexOf("/lamp/dim") != -1) {
16     irCode = 0xFF20DF;
17     lastState = "dim";
18   }
19 (...)

Добавив новые операторы else if(), вы можете оснастить скетч и другими кнопками пульта. Но эти кнопки также нужно будет добавить на веб-страницу, и для этого в код нужно будет вписать примерно следующее (здесь показаны фрагменты для кнопок «ON», «OFF», «BRIGHTEN» и «DIM»):

1 s += "<p><a href=\"/lamp/on\"><button>ON</button></a><a href=\"/lamp/off\"><button>OFF</button></a></p>";
2 s += "<p><a href=\"/lamp/brighten\"><button>BRIGHTEN</button></a><a href=\"/lamp/dim\"><button>DIM</button></a></p>";

Внеся все необходимые изменения, загрузите скетч на ESP8266.

Узнаем IP-адрес ESP8266

Загрузив скетч на ESP8266, кликните в IDE Arduino на «Инструменты» > «Монитор порта» (Tools > Serial Monitor). Когда ESP8266 загрузится, в мониторе порта должен напечататься ее IP-адрес.

Esp8266 ir led serial monitor web server ip address print 1.PNG

В моем случае это «192.168.1.22» (как на скриншоте выше). В вашем случае IP-адрес, скорее всего, будет другим. Сохраните его, чтобы затем с его помощью заходить на веб-страницу для управления ИК-лампочкой.

Демонстрация

Откройте веб-браузер на любом устройстве, подключенном к той же сети, что и ESP8266, введите в его адресную строку IP-адрес ESP8266 и нажмите на  ↵ Enter .

Поместите светодиодный ИК-передатчик рядом с ИК-лампочкой. Понажимайте на кнопки на веб-странице для управления лампочкой – поменяйте цвет, яркость, включите/выключите ее и т.д.

Альтернативный вариант серверного кода

Если у вас предыдущий вариант работает нестабильно(частые разрывы, зависания и попросту браузер не может отобразить страницу), попробуйте более стабильный вариант:

  1 #include <ESP8266WiFi.h>
  2 
  3 #ifndef UNIT_TEST
  4 #include <Arduino.h>
  5 #endif
  6 #include <IRremoteESP8266.h>
  7 #include <IRsend.h>
  8 
  9 // ИК-передатчик управляется через контакт GPIO4 (D2):
 10 IRsend irsend(4);
 11 
 12 // Вставьте здесь SSID и пароль для своей WiFi-сети:
 13 const char* ssid = "ваш ssid";
 14 const char* password = "ваш пароль";
 15 
 16 // переменная для хранения HTTP-запроса:
 17 String header;
 18 
 19 // Переменная для хранения информации о том,
 20 // какая кнопка была последней нажата на веб-странице:
 21 String lastState;
 22 
 23 // Создаем объект для сервера с портом «80»:
 24 WiFiServer server(80);
 25 
 26 void setup() {
 27   irsend.begin();
 28 
 29   Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
 30   delay(10);
 31 
 32   // Подготавливаем контакт GPIO4:
 33   pinMode(4, OUTPUT);
 34   digitalWrite(4, 0);
 35 
 36   // Подключаемся к WiFi-сети:
 37   Serial.print("Connecting to ");  //  "Подключаемся к "
 38   Serial.println(ssid);
 39 
 40   WiFi.begin(ssid, password);
 41 
 42   while (WiFi.status() != WL_CONNECTED) {
 43     delay(500);
 44     Serial.print(".");
 45   }
 46   Serial.println("WiFi connected");  //  "Подключились к WiFi"
 47 
 48   // Запускаем сервер:
 49   server.begin();
 50   Serial.println("Server started");  //  "Сервер запущен"
 51 
 52   // Печатаем IP-адрес:
 53   Serial.println(WiFi.localIP());
 54 }
 55 
 56 
 57 void loop() {
 58   // начинаем прослушивать входящих клиентов:
 59   WiFiClient client = server.available();
 60 
 61   if (client) {                     // если подключился новый клиент,
 62     Serial.println("New Client.");  // печатаем сообщение
 63     // «Новый клиент.»
 64     // в мониторе порта;
 65     String currentLine = "";        // создаем строку для хранения
 66     // входящих данных от клиента;
 67     while (client.connected()) {    // цикл while() будет работать
 68       // все то время, пока клиент
 69       // будет подключен к серверу;
 70       if (client.available()) {     // если у клиента есть данные,
 71         // которые можно прочесть,
 72         char c = client.read();     // считываем байт, а затем
 73         Serial.write(c);            // печатаем его в мониторе порта
 74         header += c;
 75         if (c == '\n') {            // если этим байтом является
 76           // символ новой строки
 77           // если получили два символа новой строки подряд,
 78           // то это значит, что текущая строчка пуста;
 79           // это конец HTTP-запроса клиента,
 80           // а значит – пора отправлять ответ:
 81           if (currentLine.length() == 0) {
 82             // HTTP-заголовки всегда начинаются
 83             // с кода ответа (например, «HTTP/1.1 200 OK»)
 84             // и информации о типе контента
 85             // (чтобы клиент понимал, что получает);
 86             // в конце пишем пустую строчку:
 87             client.println("HTTP/1.1 200 OK");
 88             client.println("Content-type:text/html");
 89             client.println("Connection: close");
 90             //  "Соединение: отключено"
 91             client.println();
 92 
 93 
 94 
 95             int irCode;
 96 
 97             if (header.indexOf("GET /lamp/on") >= 0) {
 98               irCode = 0xFFE01F;
 99               lastState = "on";
100             }
101             else if (header.indexOf("GET /lamp/off") != -1) {
102               irCode = 0xFF609F;
103               lastState = "off";
104             }
105             else if (header.indexOf("GET /lamp/brighten") != -1) {
106               irCode = 0xFFA05F;
107               lastState = "brighten";
108             }
109             else if (header.indexOf("GET /lamp/dim") != -1) {
110               irCode = 0xFF20DF;
111               lastState = "dim";
112             }
113             else if (header.indexOf("GET /lamp/red") != -1) {
114               irCode = 0xFF906F;
115               lastState = "red";
116             }
117             else if (header.indexOf("GET /lamp/green") != -1) {
118               irCode = 0xFF10EF;
119               lastState = "green";
120             }
121             else if (header.indexOf("GET /lamp/blue") != -1) {
122               irCode = 0xFF50AF;
123               lastState = "blue";
124             }
125             else if (header.indexOf("GET /lamp/yellow") != -1) {
126               irCode = 0xFF8877;
127               lastState = "yellow";
128             }
129             else if (header.indexOf("GET /lamp/cyan") != -1) {
130               irCode = 0xFF708F;
131               lastState = "cyan";
132             }
133             else if (header.indexOf("GET /lamp/purple") != -1) {
134               irCode = 0xFF6897;
135               lastState = "purple";
136             }
137             else {
138               lastState = "none";
139               Serial.println("Invalid request - IR signal not sent");
140               //  "Неправильный запрос – ИК -сигнал не отправлен"
141             }
142             // Отправляем ИК-сигнал RGB-светодиодной лампочке:
143             Serial.print("NEC: ");
144             Serial.println(irCode, HEX);
145             irsend.sendNEC(irCode, 32);
146             client.flush();
147 
148             // показываем веб-страницу:
149             client.println("<!DOCTYPE html><html>");
150             client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
151             client.println("<link rel=\"icon\" href=\"data:,\">");
152 
153             // веб-страница:
154             client.println("</head><body><h1>RGB Lamp</h1>Last state:" + lastState);
155             client.println("<p><a href=\"/lamp/on\"><button>ON</button></a><a href=\"/lamp/off\"><button>OFF</button></a></p>");
156             client.println("<p><a href=\"/lamp/brighten\"><button>BRIGHTEN</button></a><a href=\"/lamp/dim\"><button>DIM</button></a></p>");
157             client.println("<p><a href=\"/lamp/red\"><button>RED</button></a><a href=\"/lamp/green\"><button>GREEN</button></a><a href=\"/lamp/blue\"><button>BLUE</button></a></p>");
158             client.println("<p><a href=\"/lamp/yellow\"><button>YELLOW</button></a><a href=\"/lamp/cyan\"><button>CYAN</button></a><a href=\"/lamp/purple\"><button>PURPLE</button></a></p>");
159 
160             client.println("</body></html>");
161 
162             // конец HTTP-ответа задается
163             // с помощью дополнительной пустой строки:
164             client.println();
165             // выходим из цикла while():
166             break;
167           } else { // если получили символ новой строки,
168             // очищаем текущую строку «currentLine»:
169             currentLine = "";
170           }
171         } else if (c != '\r') {  // если получили любые данные,
172           // кроме символа возврата каретки,
173           currentLine += c;      // добавляем эти данные
174           // в конец строки «currentLine»
175         }
176       }
177     }
178     // очищаем переменную «header»:
179     header = "";
180     // отключаем соединение:
181     client.stop();
182     Serial.println("Client disconnected.");
183     //  "Клиент отключился."
184     Serial.println("");
185   }
186 }

Итого

Итак, с помощью этого проекта мы научились встраивать ИК-передатчик и ИК-приемник в ESP8266-проект. Это лишь шаблон, но возможности применения этих ИК-устройств – безграничны. К примеру, вместо ИК-лампочки можно управлять телевизором, кондиционером воздуха, термостатом, лентой RGB-светодиодов и любым другим устройством, управляемым с помощью пульта дистанционного управления.

Так же вы можете по аналогии с вот этим примером сделать управление лампой не через браузер,а с помощью Android-виджетов.

См.также

Внешние ссылки