От переводчика. Продолжаем изучать тему создания веб-серверов на Arduino и на микроконтроллерах вообще. В этой статье скомпонованы две части оригинального руководства — «Структура веб-страницы (HTML)» и «Arduino веб-сервер с SD картой».
Материал в этих уроках излагается последовательно и после прочтения этой статьи вы будете иметь начальное представление о внутреннем устройстве веб-страниц и принципе работы веб-сервера с SD картой в качестве хранилища этих страниц.
Другими словами, после (теоретического и практического) прохождения этих уроков, у вас появится общее представление о том, как это работает и некоторые навыки по созданию собственных веб-серверов на микроконтроллерах.
❯ Часть 3. Структура веб-страницы (HTML)
Веб-серверы Arduino, рассматриваемые в этом руководстве, используются для работы с HTML страницами (для их хранения и передачи в ответ на запрос клиента), поэтому перед дальнейшим изучением работы веб-серверов имеет смысл узнать больше о самом HTML. Этому вопросу и посвящена данная часть руководства.
Страницы и структура HTML разметки
Базовая структура HTML разметки веб-страницы показана ниже (этот код взят из предыдущего урока).
<!DOCTYPE html>
<html>
<head>
<title>Arduino Web Page</title>
</head>
<body>
<h1>Hello from Arduino!</h1>
<p>A web page from the Arduino server</p>
</body>
</html>
HTML теги
Код HTML разметки состоит из тегов, заключенных в угловые скобки: < >
Название (тип) HTML тега размещается между открывающей и закрывающей угловыми скобками.
Большинство тегов являются двойными, то есть имеют открывающую и закрывающую части. Текст или объект, находящийся между открывающей и закрывающей частями тегов, воспринимается и форматируется браузером в соответствии с типами этих тегов. Закрывающий тег отличается от открывающего наличием слеша (косой черты) после открывающей угловой скобки. Например:
<p>Текст абзаца...</p> — здесь тег абзаца (<p>) используется, чтобы сообщить браузеру, что текст между открывающим <p> и закрывающим </p> является абзацем текста. В результате браузер отформатирует его соответствующим образом.
Существуют также одиночные теги, без закрывающей части. Примером такого тега является перевод строки, который перемещает вывод на следующую строку. Этот тег записывается как <br> (в соответствии со стандартом HTML) или <br /> (в более полной версии и в соответствии со стандартом XHTML).
Изучение языка HTML (HyperText Markup Language) заключается в изучении HTML тегов: какие бывают типы тегов, как они работают и какие теги и как можно использовать совместно.
Структура веб-страницы
Веб-страницы состоят из двух основных разделов — раздела заголовка и раздела тела страницы. Эти два раздела размещаются между открывающим и закрывающим тегами html, как показано ниже.
<html>
<head>
</head>
<body>
</body>
</html>
Само содержимое веб-страницы (видимая её часть и интерактивные элементы на ней) размещаются между тегами body.
Служебная (мета) информация, которая не отображаются непосредственно на странице, помещается между тегами заголовка head, например, там находится текст заголовка, который отображается на вкладке страницы веб-браузера. Также в раздел заголовка может включаться дополнительный код, например, описание стилей оформления (CSS).
Основные HTML теги
Мы уже познакомились с некоторыми HTML тегами, например тегом абзаца — <p> и тегами разметки структуры HTML страницы — <html>, <head> и <body>. Ниже приведено описание ещё двух HTML тегов, которые использовались нами в предыдущем уроке о базовом сервере Arduino.
С другими тегами мы будем знакомиться по мере их использования в наших уроках.
Тег заголовка
Заголовки браузер выделяет полужирным шрифтом и большим, чем у обычного текста, размером. В нашем первом Arduino сервере использовался тег заголовка 1 — <h1>. Это заголовок верхнего уровня (то есть главный на странице). Текст, расположенный между тегами <h1> и </h1>, воспринимается браузером как заголовок 1-го уровня.
Подзаголовки имеют меньший размер, чем текст заголовка h1 и обозначается как h2, h3, h4 и т. д. (<h2>, <h3>, <h4> и т. д.)
Основной заголовок h1 используется как заглавие всей страницы, например, главы («Глава 1»), h2 обозначает подзаголовок, например, части 1.1, 1.2, 2.1 и т. д., h3 обозначает подзаголовок заголовка h2, например 1.1.1. и 1.1.2 и т. д.
Каждый последующий уровень заголовков будет отображаться браузером всё более и более мелким шрифтом.
Тег title
Тег <title> размещается в разделе <head> HTML страницы и содержит текст, который отображается на вкладке этой страницы в веб-браузере.
Пример веб-страницы
Приведённый ниже пример веб-страницы на самом деле не полностью соответствует спецификации HTML разметки, а просто напрямую размещает текст между открывающим и закрывающим тегами <html>. В большинстве случаев это работает, но лучше использовать HTML код, соответствующий стандарту.
В этом примере каждая строка заканчивается тегом <br />, что приводит к отображению в браузере новых строк под предыдущими (иначе бы вся информация выводилась в одной строке). На следующем скриншоте показаны вид страницы в браузере и HTML код, используемый для её создания.
Веб-страница — слева, её HTML код — справа.
Больше об HTML
С новыми HTML тегами мы будем знакомиться постепенно, по мере освоения этого руководства, но, если вам интересно, то вы можете узнать больше об этой теме в интернете или прочитав учебник по HTML.
❯ Часть 4. Arduino веб-сервер с SD картой
В данном уроке рассматривается работа веб-сервера, который хранит страницу не внутри скетча Arduino, а на microSD карте памяти. Комплект оборудования для этого веб-сервера состоит из трёх компонентов: контроллера Arduino, платы Ethernet Shield и microSD карты памяти. Когда браузер запрашивает страницу у веб-сервера Arduino, контроллер извлекает её с SD карты и передаёт в ответ на этот запрос.
Создание веб-страницы
Поскольку веб-страница должна храниться на SD карте, то её необходимо сначала создать при помощи текстового редактора, а затем скопировать на карту в виде файла. Для создания этого файла вы можете использовать, например, штатный «Блокнот» в Windows (или аналогичный редактор в вашей операционной системе).
Скопируйте нижеприведённый код веб-страницы в текстовый редактор и затем сохраните его в виде файла index.htm.
<!DOCTYPE html>
<html>
<head>
<title>Arduino SD Card Web Page</title>
</head>
<body>
<h1>Hello from the Arduino SD Card!</h1>
<p>A web page from the Arduino SD card server.</p>
</body>
</html>
Это та же самая страница, с которой мы имели дело в предыдущем уроке, только с несколько изменённым текстом. Вы можете протестировать её работу, открыв в веб-браузере (кликнув мышкой по названию файла или перетащив его в окно браузера).
Копирование веб-страницы
Для копирования файла index.htm на карту памяти вам понадобится компьютер со слотом microSD или отдельным картридером соответствующего формата.
Вставьте вашу microSD карту в слот и скопируйте на неё файл index.htm так, как вы обычно копируете файлы.
Затем вставьте SD карту в слот на плате Ethernet Shield.
❯ Веб-сервер с SD картой
Аппаратное обеспечение
Для работы с сервером у вас должна быть microSD карта со скопированной на нее веб-страницей, вставленная в слот на Ethernet Shield. Сама плата Ethernet Shield должна быть подключена к контроллеру Arduino и при помощи Ethernet кабеля — к вашей локальной сети. Питание системы должно осуществляться через USB кабель, подключённый к соответствующему порту на вашем компьютере.
Скетч Ардуино
Ниже представлен скетч Arduino, который извлекает веб-страницу из SD карты памяти и отправляет её в ответ на запрос браузера.
/*--------------------------------------------------------------
Скетч: eth_websrv_SD
Описание: Arduino веб-сервер со страницей, хранящейся на SD карте памяти
Оборудование: Arduino Uno, Arduino Ethernet Shield и micro SD карта памяти, отформатированная в FAT16
Программное обеспечение: cреда разработки Arduino IDE, SD карта памяти с веб-страницей в файле index.htm
Ссылки:
- WebServer example by David A. Mellis and modified by Tom Igoe
- SD card examples by David A. Mellis and Tom Igoe
- Ethernet library documentation: http://arduino.cc/en/Reference/Ethernet
- SD Card library documentation: http://arduino.cc/en/Reference/SD
Дата создания: 10 января 2013
Автор: W.A. Smith, http://startingelectronics.org
--------------------------------------------------------------*/
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10, 0, 0, 20); // IP-адрес (нужно изменить на актуальный для вашей сети)
EthernetServer server(80);
File webFile;
void setup() {
Ethernet.begin(mac, ip);
server.begin();
Serial.begin(115200);
// Инициализируем SD карту
Serial.println("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("ERROR - SD card initialization failed!");
return; // Ошибка инициализации
}
Serial.println("SUCCESS - SD card initialized.");
// Проверка наличия файла index.htm
if (!SD.exists("index.htm")) {
Serial.println("ERROR - Can't find index.htm file!");
return; // файл index не найден
}
Serial.println("SUCCESS - Found index.htm file.");
}
void loop() {
EthernetClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
// посылка веб-страницы
webFile = SD.open("index.htm"); // открываем файл index.htm
if (webFile) {
while(webFile.available()) {
client.write(webFile.read()); // посылаем веб-страницу клиенту
}
webFile.close();
}
break;
}
if (c == '\n') {
currentLineIsBlank = true;
}
else if (c != '\r') {
currentLineIsBlank = false;
}
} // end if (client.available())
} // end while (client.connected())
delay(1);
client.stop();
} // end if (client)
}
Использование скетча
Скопируйте вышеприведенный код и вставьте его в новый скетч Arduino IDE. Загрузите скетч в контроллер и затем с помощью браузера перейдите по IP-адресу, указанному в скетче. Если на предыдущих этапах вы всё сделали правильно, то созданная вами веб-страница должна отобразиться в браузере.
Примечание переводчика. Различные нюансы и проблемы с работой сервера были разобраны в предыдущей части руководства. Поэтому, если у вас возникли какие-то проблемы с работой веб-сервера из этого урока, то рекомендуется ещё раз внимательно прочитать предыдущую часть.
Возможные проблемы
Если скетч из предыдущего урока работал, то единственное, что может пойти не так, — это инициализация SD карты или поиск на ней файла index.htm. Если файла нет на карте или его название не соответствует ожидаемому index.htm, то сервер не сможет передать веб-страницу в ответ на запрос браузера.
Чтобы получить больше информации о проблеме, откройте окно Serial Monitor среды разработки Arduino: в этом окне выводится диагностическая информация о работе SD карты и это может помочь вам выявить причину неисправности.
Объяснение работы скетча
Этот скетч представляет собой модифицированную версию скетча из предыдущей части «Базовый вариант Arduino веб-сервера» и здесь предполагается, что вы знакомы как с теорией, так и практикой предыдущего урока.
Дополнения в коде
Новый вариант скетча инициализирует SD карту в функции setup() и отправляет соответствующую диагностическую информацию в Serial порт. Эти данные можно увидеть в окне Serial Monitor среды Arduino.
Вместо отправки веб-страницы построчно из кода скетча, как в предыдущем уроке, новый вариант веб-сервера открывает файл index.htm с SD карты и отправляет его содержимое клиенту (браузеру).
❯ От переводчика о 3-й и 4-й частях
Определённо, раздел «Объяснение работы скетча» является чем-то шедевральным ко краткости изложения. Чтобы так кратко объяснять сложные вещи, несомненно нужно иметь талант (смайл).
На самом деле вся работа по осмыслению работы «веб-сервера с SD картой» возложена на самого пользователя и авторами руководства предполагается, что вы потратите некоторое время и усилия на анализ работы кода и практические эксперименты с работой сервера.
От себя ещё раз напомню: не забывайте о практике и не игнорируйте практическую работу с новым вариантом веб-сервера — это очень важно для успешного освоения руководства в целом.
3ton
Давно хотел заняться подобным вопросом и ваша статья прям подталкивает чтоб заняться этим вплотную. Но интересует несколько моментов.
можно ли использовать в программном цикле не только вебсервер(суть то платы не в том чтоб ведом мир порадовать), т.е. иметь несколько задач передавая поочередно управление между их циклами(так сказать многозадачность эмулировать)
использовать плату не только для информирования по запросу клиента, но и при событии. К примеру включили оборудование, открыли дверь, сработал какой-нибудь датчик и плата создает оповещение клиенту.
smart_alex Автор
Можно и первый пункт и второй и ещё ровно миллион вещей — легче сказать чего нельзя сделать, используя эту технологию.
Вот ролики с примерами работы подобных веб-серверов для Mega, Due, 101 и ESP8266:
https://www.youtube.com/channel/UCzwiCsCitrMphSTIEr8It_w
farafonoff
Если не для учебных целей, а для бытового продакшна, стоит смотреть в сторону MQTT, результат получится более предсказуемым и унифицированным чем интеграция десятка самодельных http эндпоинтов
3ton
да, для практичного применения хочу заюзать.
как самый актуальный пример:
в доме имеется котельная на 2 контура на газе. и хотелось бы сделать на подобном устройстве контроль сжигания газа и отдельно контроль насоса каждого контура, чтоб проанализировать использование и модифицировать цикличность использования как насосов на контурах, так и подачи газа. Котел устанавливался застройщиком с запасом, а последние зимы довольно таки теплые, вот и получается что даже на минимальном режиме работы котел производит тепла больше необходимого.
farafonoff
На базе MQTT очень много готовых компонентов, для быстрого старта самое то. Есть всякие low-code решения (https://nodered.org/), для просто мониторинга есть такие штуки https://grafana.com/grafana/plugins/grafana-mqtt-datasource/. Есть множество готовых прошивок для всяких контроллеров (esp8266) с уже реализованным OTA.
sav13
Все это можно сделать, например навесить задачи на таймеры. Все события реализовывать по прерываниям
Только мне кажет имеет смысл взглянуть в сторону ESP32
При очень доступной цене там по сравнению с Arduino UNO ооочень много памяти, два ядра и FreeRTOS "из коробки". Ethernet к нему прикручивается без проблем, если неохота WiFi юзать