ESP8266:Примеры/Управление ESP8266 при помощи Android-виджета
Черновик |
Управление ESP8266 при помощи Android-виджета
В этом проекте мы воспользуемся вот этим скетчем, с помощью которого создается защищенный паролем веб-сервер, управляющий включением/выключением двух GPIO-контактов ESP8266. Этот метод требует открытия браузера и вписывания IP-адреса, но гораздо проще было бы управлять GPIO-контактами ESP8266 прямо с экрана вашего смартфона. Именно описанием этого метода мы в этом руководстве и займемся.
Необходимое оборудование
- Плата ESP8266 - 1шт.;
- Светодиод - 2шт.;
- Резистор 470 Ом- 2 шт.
- Макетная плата - 1шт.;
- Провода перемычки.
- Android-устройство(планшет, смартфон, часы, приставка и т.д.) - 1шт.
Как работает код
В самом начале скетча мы подключаем библиотеку «ESP8266WiFi», а в следующих двух строчках задаем SSID и пароль для своей WiFi-сети, чтобы ESP8266 мог к ней подключиться.
// Подключаем библиотеку «ESP8266WiFi»:
#include <ESP8266WiFi.h>
// Пишем SSID и пароль для своей WiFi-сети:
const char* ssid = "YOUR_NETWORK_NAME";
const char* password = "YOUR_NETWORK_PASSWORD";
Далее создаем объект веб-сервера и задаем ему порт «8888»:
// Создаем объект веб-сервера с номером порта «8888»:
WiFiServer server(8888);
Создаем переменную «header» для хранения заголовка ответа на запрос, переменные «gpio5_state» и «gpio4_state» для хранения текущего состояния этих GPIO-контактов, а также переменные «gpio5_pin» и «gpio4_pin» для хранения номеров контактов GPIO4 и GPIO5.
// Создаем несколько переменных:
String header;
String gpio5_state = "Off";
String gpio4_state = "Off";
int gpio5_pin = 5;
int gpio4_pin = 4;
Далее создаем блок setup(), код в котором будет запущен только раз – при запуске ESP8266.
// Код в этом блоке будет запущен только один раз:
void setup() {
}
Запускаем последовательную коммуникацию на скорости 115200 бод (для отладки). Переключаем оба GPIO-контакта в режим вывода данных (OUTPUT) и задаем им значение «LOW».
// Этот код будет запущен только один раз:
void setup() {
// Инициализируем последовательную коммуникацию (для отладки):
Serial.begin(115200);
delay(10);
// Подготавливаем GPIO-контакты:
pinMode(gpio5_pin, OUTPUT);
digitalWrite(gpio5_pin, LOW);
pinMode(gpio4_pin, OUTPUT);
digitalWrite(gpio4_pin, LOW);
В следующем фрагменте кода запускаем подключение к WiFi-сети, ждем успешного подключения и печатаем в мониторе порта IDE Arduino IP-адрес ESP8266.
// Подключаемся к WiFi-сети:
Serial.println();
Serial.print("Connecting to ");
// "Подключаемся к "
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// "Подключились к WiFi"
// Запускаем веб-сервер:
server.begin();
Serial.println("Web server running. Waiting for the ESP IP...");
// "Веб-сервер запущен.
// "Ждем получения IP-адреса ESP8266..."
delay(1000);
// Печатаем IP-адрес ESP8266:
Serial.println(WiFi.localIP());
}
Блок loop() отвечает за то, что будет происходить, когда новый клиент установит соединение с веб-сервером. То есть код в loop() будет постоянно прослушивать новых клиентов. Соответственно, если к веб-серверу подключится новый клиент, он начнет подключаться к нему.
// Код в блоке loop() будет постоянно повторяться:
void loop() {
// Прослушиваем новых клиентов:
WiFiClient client = server.available();
Булева переменная «blank_line» ниже служит для того, чтобы определить конец HTTP-запроса. Кроме того, в этом фрагменте кода используется цикл while(), который будет работать все то время, пока клиент будет подключен к веб-серверу.
if (client) {
Serial.println("New client"); // "Новый клиент"
// Булева переменная, предназначенная
// для определения конца HTTP-запроса:
boolean blank_line = true;
while (client.connected()) {
if (client.available()) {
Теперь давайте добавим в веб-сервер механизм аутентификации, чтобы сделать его более безопасным. После этого любому, кто попытается получить доступ к веб-серверу, придется ввести имя пользователя и пароль.
По умолчанию именем пользователя будет «user», а паролем – «pass». Чуть ниже я расскажу о том, как их поменять. Если пользователь введет правильные имя пользователя и пароль, то получит доступ к веб-странице для управления GPIO-контактами ESP8266.
// Проверяем, правильные ли введены имя пользователя и пароль:
if(header.indexOf("dXNlcjpwYXNz") >= 0) {
В следующем фрагменте кода проверяется, на какую кнопку веб-страницы нажал пользователь. По сути, в нем проверяется, какой вы хотите открыть URL.
К примеру, кликая на кнопку «OFF» для контакта GPIO5, вы открываете ссылку «http://192.168.1.22:8888/gpio5off». Код смотрит на эту ссылку и при помощи нескольких else if() сверяется с тем, что ему нужно сделать. В случае со ссылкой «http://192.168.1.22:8888/gpio5off» он переключит контакт GPIO5 («gpio5_pin») в состояние «LOW».
// Проверяем, правильные ли введены
// имя пользователя и пароль:
if(header.indexOf("dXNlcjpwYXNz") >= 0) {
// Залогинивание прошло успешно:
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
// "Соединение: отключено"
client.println();
// Включаем/выключаем GPIO-контакты:
if(header.indexOf("GET / HTTP/1.1") >= 0) {
Serial.println("Main Web Page");
// "Главная веб-страница"
}
else if(header.indexOf("GET /gpio5on HTTP/1.1") >= 0){
Serial.println("GPIO 5 On");
// "Контакт GPIO5 включен"
gpio5_state = "On";
digitalWrite(gpio5_pin, HIGH);
}
else if(header.indexOf("GET /gpio5off HTTP/1.1") >= 0){
Serial.println("GPIO 5 Off");
// "Контакт GPIO5 выключен"
gpio5_state = "Off";
digitalWrite(gpio5_pin, LOW);
}
else if(header.indexOf("GET /gpio4on HTTP/1.1") >= 0){
Serial.println("GPIO 4 On");
// "Контакт GPIO4 включен"
gpio4_state = "On";
digitalWrite(gpio4_pin, HIGH);
}
else if(header.indexOf("GET /gpio4off HTTP/1.1") >= 0){
Serial.println("GPIO 4 Off");
// "Контакт GPIO4 выключен"
gpio4_state = "Off";
digitalWrite(gpio4_pin, LOW);
}
Страница отправляется клиенту при помощи метода client.println(). Это очень простая веб-страница, использующая фреймворк Bootstrap (см. код ниже).
Более подробно о Bootstrap можно почитать по этой ссылке.
На веб-странице будет 4 кнопки для включения/выключения (переключения между состояниями «HIGH» и «LOW») двух светодиодов, подключенных к контактам GPIO5 и GPIO4.
Кнопки – это HTML-теги <a href=””></a> с CSS-классом, который придает им вид кнопки. Когда вы нажимаете на кнопку, вам открывается другая страница с URL, соответствующим этой кнопке. Именно так ESP8266 и узнает, что ей нужно сделать (т.е. включить или выключить светодиод, и какой именно).
// Ваша веб-страница:
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
client.println("<meta name=\"viewport\" content=\"width=device-width, initialscale=1\">");
client.println("<link rel=\"stylesheet\"
href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css\">");
client.println("</head><div class=\"container\">");
client.println("<h1>Web Server</h1>");
client.println("<h2>GPIO 5 - Current State: " + gpio5_state);
client.println("<div class=\"row\">");
client.println("<div class=\"col-md-2\"><a href=\"/gpio5on\" class=\"btn btn-block
btn-lg btn-success\" role=\"button\">ON</a></div>");
client.println("<div class=\"col-md-2\"><a href=\"/gpio5off\" class=\"btn btn-block
btn-lg btn-danger\" role=\"button\">OFF</a></div>");
client.println("</div>");
client.println("<h2>GPIO 4 - Current State: " + gpio4_state);
client.println("<div class=\"row\">");
client.println("<div class=\"col-md-2\"><a href=\"/gpio4on\" class=\"btn btn-block
btn-lg btn-success\" role=\"button\">ON</a></div>");
client.println("<div class=\"col-md-2\"><a href=\"/gpio4off\" class=\"btn btn-block
btn-lg btn-danger\" role=\"button\">OFF</a></div>");
client.println("</div></div></html>");
Если вы введете неправильные имя пользователя и пароль, в браузере будет напечатано сообщение «Authentication failed» («Аутентификация не удалась»).
// Неправильные имя пользователя и пароль,
// поэтому HTTP-запрос завершился неудачей...
else {
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println();
client.println("<html>Authentication failed</html>");
}
Строчки кода в конце скетча очищают переменную «header», завершают цикл loop() и завершают подключение.
header = "";
break;
}
if (c == '\n') {
// Когда нужно перейти к следующей строчке:
blank_line = true;
}
else if (c != '\r') {
// Когда в текущей строке найден символ:
blank_line = false;
}
}
}
// Завершаем подключение к клиенту:
delay(1);
client.stop();
Serial.println("Client disconnected.");
// "Клиент отключился."
}
}
Как задать собственные имя пользователя и пароль
В скетче, который мы разобрали выше, именем пользователя является «user», а паролем – «pass». Уверен, вы захотите задать вместо них собственные имя пользователя и пароль. Пройдите по этой ссылке. В первом поле впишите следующее:
your_username:your_password
Примечание: Обратите внимание, что между именем пользователя и паролем нужно вписать «:».
В моем случае это «user:pass».
Затем нажмите на зеленую кнопку «Encode» – это сгенерирует строку в формате Base64. В моем случае это «dXNlcjpwYXNz».
Скопируйте ее и вставьте в это место скетча:
// Проверяем, правильные ли введены имя пользователя и пароль:
if(header.indexOf("dXNlcjpwYXNz") >= 0) {
Совет: Эта 80-ая строчка скетча, и в ней также присутствует оператор if().
Загружаем код
Подключите ESP8266 к ПК и откройте IDE Arduino. Кликните по «Инструменты» > «Плата» (Tools > Board) и выберите подключенную плату.
Выберите COM-порт, к которому подключена ваша плата.
Проверив все настройки, нажмите на кнопку «Загрузка» (Upload):
Подождите несколько секунд, пока не увидите сообщение «Загрузка завершена» (Done uploading) в левом нижнем углу IDE Arduino.
Копируем IP-адрес ESP8266
Загрузив веб-серверный скетч на ESP8266, кликните в IDE Arduino на «Инструменты» > «Монитор порта» (Tools > Serial Monitor). Монитор порта – это окно, где ESP8266, загрузившись, напечатает свой IP-адрес.
Мой IP-адрес – это «192.168.1.22» (см. на скриншоте ниже). Ваш IP-адрес, скорее всего, будет другим. Сохраните его, т.к. позднее вы с его помощью перейдете на страницу веб-сервера.
Важно: Выставьте скорость монитора порта на 115200 бод, иначе вы просто ничего не увидите.
Проблема – В мониторе порта не печатается IP-адрес
Если у вас возникла такая проблема, можно попробовать сделать следующее:
- Оставьте монитор порта открытым;
- ESP-12E (или FTDI-программатор) должен оставаться подключенным к ПК;
- Перезапустите ESP-12E, нажав на встроенную в него кнопку.
Спустя секунду ESP8266 должна напечатать в мониторе порта свой IP-адрес.
Устанавливаем программу для сканирования IP-адресов
Если IP-адрес в мониторе порта по-прежнему не появляется, то вам нужно будет установить на свой ПК программу для сканирования IP-адресов. Она будет искать все девайсы в вашей сети.
- Загрузите ее (это бесплатно). Можете выбрать между Advanced IP Scanner (Windows) и Angry IP Scanner (MAC OS X, Windows или Linux);
- Установите программу (в это время ESP8266 должен быть включен, и на нем должен работать скетч, написанный нами выше);
- Откройте программу для сканирования IP-адресов и нажмите на кнопку «Сканировать» (Scan);
Дайте процессу завершиться (это должно занять несколько минут).
Заходим на веб-сервер
Перед заходом на веб-сервер нужно сделать следующее:
- Перезапустите ESP8266;
- Откройте браузер;
- Впишите в его адресную строку IP-адрес, скопированный ранее из монитора порта IDE Arduino, и добавьте в конце «8888» (в моем случае – «192.168.1.22:8888»);
- Нажмите на ↵ Enter .
После этого в браузере должно выскочить окно с запросом ввести имя пользователя и пароль:
- Введите имя пользователя и пароль
- Залогиньтесь
В результате в браузере должна загрузиться примерно такая страница:
Примечание: Чтобы получить доступ к веб-серверу, устройство с браузером должно быть подключено к тому же роутеру, что и ESP8266.
Устанавливаем приложение HTTP Request Shortcuts
Для этого проекта мы воспользуемся бесплатным Android-приложением HTTP Request Shortcuts, позволяющим выполнять HTTP-запросы GET/POST простым нажатием на кнопку прямо на домашнем экране смартфона, избавляя от необходимости вбивать IP-адрес ESP8266 в браузер.
Поищите в онлайн-магазине Google Play Store «HTTP Request Shortcuts», а затем установите приложение. Далее кликните на кнопку «Открыть».
Создаем кнопку «ON» («ВКЛ») для контакта GPIO5
Чтобы создать виджет, при нажатии переключающий контакт GPIO5 в состояние «ON», кликните по синей кнопке с плюсом в правом нижнем углу приложения.
Выберите пункт «From scratch».
Вы можете задать следующие настройки виджета:
- Shortcut name (Название виджета): ON – GPIO5;
- Иконка: Изображение, показываемое на домашнем экране смартфона;
- Method (Тип запроса): GET;
- URL (ссылка): Здесь нужно вписать «http://IP_АДРЕС_ВАШЕЙ_ESP:8888/gpio5on». В моем случае получилась ссылка «http://192.168.1.22:8888/gpio5on»;
- Authentication Method (Метод аутентификации) – Basic Authentication (Базовая аутентификация)
- Username (Имя пользователя) – user
- Password (Пароль) – pass
- Response Type (Тип ответа) – Simple Toast (Простое уведомление)
- Timeout (Таймаут) – short (3 seconds) (короткий (3 секунды))
- Delay execution (Задержка выполнения) – No delay (Без задержки)
- When not connected to the internet (Когда не подключен к интернету) – drop the request (отклонить запрос)
Чтобы сохранить настройки, кликните на галочку в правом верхнем углу экрана.
Создаем кнопку «OFF» («ВЫКЛ») для контакта GPIO5
Нам также нужно будет создать кнопку «OFF» для контакта GPIO5. Вот ее настройки:
- Shortcut name: OFF – GPIO5;
- Иконка. Изображение, показываемое на домашнем экране смартфона;
- Method: GET;
- URL: Здесь нужно вписать «http://IP_АДРЕС_ВАШЕЙ_ESP:8888/gpio5off». В моем случае получилась ссылка «http://192.168.1.22:8888/gpio5off»;
- Authentication Method: Basic Authentication;
- Username: user;
- Password: pass;
- Response Type: Simple Toast;
- Timeout: short (3 seconds);
- Delay execution: No delay;
- When not connected to the internet: drop the request;
Чтобы сохранить настройки, нажмите на галочку в правом верхнем углу экрана.
Добавляем виджеты на домашний экран
Чтобы добавить виджет на домашний экран смартфона, просто зажмите кнопку «ON – GPIO 5».
В появившемся меню выберите пункт «Place on home screen» (Разместить на домашнем экране). Потом сделайте то же самое для виджета «OFF – GPIO 5».
Тестируем
Обе иконки должны появиться на домашнем экране смартфона. Теперь попробуйте понажимать на виджеты. Если при нажатии на них GPIO-контакты ESP8266 меняют значение с «ON» на «OFF» и обратно, то все работает как надо.
Вот и все. Код, загруженный на ESP8266, также готов для управления контактом GPIO4. Поэтому рекомендую проделать для его настройки все те же шаги, что и для настройки GPIO5. Кроме того, этот проект можно без труда перенастроить и под управление другими устройствами.
Схема
Загрузив код на ESP8266, подключите компоненты друг к другу, как показано на схеме ниже (для подключения светодиодов можно воспользоваться резисторами номиналом между 270 Ом и 470 Ом).
Код
/*********
Rui Santos
Complete project details at http://randomnerdtutorials.com
*********/
// Including the ESP8266 WiFi library
#include <ESP8266WiFi.h>
// Replace with your network details
const char* ssid = "YOUR_NETWORK_NAME";
const char* password = "YOUR_NETWORK_PASSWORD";
// Web Server on port 8888
WiFiServer server(8888);
// variables
String header;
String gpio5_state = "Off";
String gpio4_state = "Off";
int gpio5_pin = 5;
int gpio4_pin = 4;
// only runs once
void setup() {
// Initializing serial port for debugging purposes
Serial.begin(115200);
delay(10);
// preparing GPIOs
pinMode(gpio5_pin, OUTPUT);
digitalWrite(gpio5_pin, LOW);
pinMode(gpio4_pin, OUTPUT);
digitalWrite(gpio4_pin, LOW);
// Connecting to WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Starting the web server
server.begin();
Serial.println("Web server running. Waiting for the ESP IP...");
delay(1000);
// Printing the ESP IP address
Serial.println(WiFi.localIP());
}
// runs over and over again
void loop() {
// Listenning for new clients
WiFiClient client = server.available();
if (client) {
Serial.println("New client");
// boolean to locate when the http request ends
boolean blank_line = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
header += c;
if (c == '\n' && blank_line) {
// checking if header is valid
// dXNlcjpwYXNz = 'user:pass' (user:pass) base64 encode
Serial.print(header);
// Finding the right credential string
if(header.indexOf("dXNlcjpwYXNz") >= 0) {
//successful login
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
if(header.indexOf("GET / HTTP/1.1") >= 0) {
Serial.println("Main Web Page");
}
else if(header.indexOf("GET /gpio5on HTTP/1.1") >= 0){
Serial.println("GPIO 5 On");
gpio5_state = "On";
digitalWrite(gpio5_pin, HIGH);
}
else if(header.indexOf("GET /gpio5off HTTP/1.1") >= 0){
Serial.println("GPIO 5 Off");
gpio5_state = "Off";
digitalWrite(gpio5_pin, LOW);
}
else if(header.indexOf("GET /gpio4on HTTP/1.1") >= 0){
Serial.println("GPIO 4 On");
gpio4_state = "On";
digitalWrite(gpio4_pin, HIGH);
}
else if(header.indexOf("GET /gpio4off HTTP/1.1") >= 0){
Serial.println("GPIO 4 Off");
gpio4_state = "Off";
digitalWrite(gpio4_pin, LOW);
}
// your web page
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head>");
client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css\">");
client.println("</head><div class=\"container\">");
client.println("<h1>Web Server</h1>");
client.println("<h2>GPIO 5 - Current State: " + gpio5_state);
client.println("<div class=\"row\">");
client.println("<div class=\"col-md-2\"><a href=\"/gpio5on\" class=\"btn btn-block btn-lg btn-success\" role=\"button\">ON</a></div>");
client.println("<div class=\"col-md-2\"><a href=\"/gpio5off\" class=\"btn btn-block btn-lg btn-danger\" role=\"button\">OFF</a></div>");
client.println("</div>");
client.println("<h2>GPIO 4 - Current State: " + gpio4_state);
client.println("<div class=\"row\">");
client.println("<div class=\"col-md-2\"><a href=\"/gpio4on\" class=\"btn btn-block btn-lg btn-success\" role=\"button\">ON</a></div>");
client.println("<div class=\"col-md-2\"><a href=\"/gpio4off\" class=\"btn btn-block btn-lg btn-danger\" role=\"button\">OFF</a></div>");
client.println("</div></div></html>");
}
// wrong user or passm, so http request fails...
else {
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println();
client.println("<html>Authentication failed</html>");
}
header = "";
break;
}
if (c == '\n') {
// when starts reading a new line
blank_line = true;
}
else if (c != '\r') {
// when finds a character on the current line
blank_line = false;
}
}
}
// closing the client connection
delay(1);
client.stop();
Serial.println("Client disconnected.");
}
}