2. Сконвертируем изображение в base64-формат, для этого можно воспользоваться любым онлайн-конвертором, например этим: https://www.base64-image.de.
Мы получим строку такого вида:
data:image/jpeg;base64,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
3. Создадим текстовую переменную, которая будет хранить наше изображение и скопируем в нее всю строку:
const PROGMEM char *image01 = "data:image/jpeg;base64,/9j/4A….5n/2Q==”;
Тег PROGMEM указывает компилятору, что это константа, которую можно хранить во флеш-памяти, сэкономив тем самым место для других переменных. Это особенно актуально, если картинок много.
4. Теперь мы можем использовать наше изображение с помощью тега img следующим образом:
<img src="data:image/jpeg;base64...5n/2Q==">
Для этого добавим следующий код в следующую строку после “Turn LED off”:
client.print("<img src=\""); client.print(image01); client.print("\">");
Наш веб-сервер вряд ли получит премию года за лучший дизайн, но по крайней мере, пользователь теперь видит, что он управляет именно светодиодами:
Кстати, в реальном проекте все изображения целесообразно вынести в отдельный файл, который можно назвать например, “images.h”. Тогда в основной программе можно будет написать #include "images.h". Это позволит отделить ресурсы от кода, и сделать текст программы более читаемым.
Самостоятельная работа: вывести разные типы изображений, например кнопки, светодиоды.
3.11 Удаленный мониторингС помощью web-сервера можно не только включать и выключать светодиод, но и получать информацию с удаленного объекта. Например, можно узнать температуру в квартире, находясь на каникулах или в отпуске. Как нетрудно догадаться, для этого достаточно вывести нужные нам параметры в HTML, который и отобразится на веб-странице.
К примеру, достаточно добавить такую строку в код формирования HTML:
if (digitalRead(buttonPin) == HIGH) {
client.print("Button state: ON<br>");
} else {
client.print("Button state: OFF<br>");
}
При обновлении страницы в браузере мы увидим соответствующий текст. Разумеется, это может быть не только кнопка, но и например, датчик закрывания двери или датчик освещенности (желающие могут перечитать главу 2.6 “Ввод аналоговых величин”).
Рассмотрим пример подробнее. Допустим, у нас есть данные с разных сенсоров (подробнее можно прочитать в главе 2.7-2.10). Чтобы не загромождать тестовый код, представим данные в виде уже готовых переменных, реальный код чтения желающие могут добавить самостоятельно.
float temperature = 22.5;
int humidity = 60;
int pressure = 1010;
bool doorClosed = true;
bool windowClosed = false;
Наша задача - отобразить эти данные на веб-сервере, для чего проще всего воспользоваться HTML-тегом “Table” (таблица).
Пример таблицы в HTML:
<table border = "1">
<tr>
<td>Row 1, Column 1</td>
<td>Row 1, Column 2</td>
</tr>
<tr>
<td>Row 2, Column 1</td>
<td>Row 2, Column 2</td>
</tr>
</table>
В браузере это будет выглядеть вот так:
Здесь tr - это table row, строка таблицы, а td - это элемент ячейки. Таким образом, мы можем группировать данные так, как нам удобно. Добавим таблицу в наш сервер. Для экономии места будет приведена только функция loop, остальное не изменилось.
void loop() {
// Возобновление соединения при необходимости
while (WiFi.status() != WL_CONNECTED) {
delay(500);
WiFi.begin(ssid, password);
Serial.print(".");
}
// Данные с датчиков
float temperature = 22.5;
int humidity = 60;
int pressure = 1010;
bool doorClosed = true;
bool windowClosed = false;
// Здесь можно добавить код чтения
// ...
WiFiClient client = server.available();
if (client) {
Serial.println("New Client.");
String currentLine = "";
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n') {
if (currentLine.length() == 0) {
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println();
client.print("<html>");
client.print("<head><title>ESP32 Server</title></head>");
client.print("<body>");
client.print("<h3>ESP32 sensors data</h3>");
client.print("<table border = \"1\">");
client.print(" <tr><td>Temperature, C</td><td>");
client.print(String(temperature)); client.print("</td></tr>");
client.print(" <tr><td>Humidity, percent</td><td>");
client.print(String(humidity)); client.print("</td></tr>");
client.print(" <tr><td>Pressure, hPa</td><td>");
client.print(String(pressure)); client.print("</td></tr>");
client.print(" <tr><td>Door closed:</td><td>");
client.print(doorClosed ? "yes" : "no"); client.print("</td></tr>");
client.print(" <tr><td>Window closed:</td><td>");
client.print(windowClosed ? "yes" : "no"); client.print("</td></tr>");
client.print("</table>");
client.print("");
client.print("</body></html>");
client.println();
break;
} else {
currentLine = "";
}
} else if (c != '\r') {
currentLine += c;
}
}
}
client.stop();
Serial.println("Client Disconnected.");
}
}
Как можно видеть, код довольно прост. Мы сформировали таблицу с нужными нам полями. Для вывода строк yes/no мы использовали конструкцию языка С doorClosed ? "yes" : "no", она позволяет выбрать одно из двух значений в зависимости от условия.
Запускаем браузер, и видим данные с нашего сервера:
Теперь мы можем оставить устройство подключенным, и наблюдать состояние дома или квартиры удаленно, с любой точки земного шара.
Самостоятельная работа #1: подключить реальные датчики, например