
От переводчика. На шестом уроке мы добрались до практически полезного кода — с его помощью можно создать работающий пример «бесшовного» автоматического взаимодействия между клиентом (страницей в веб-браузере) и Arduino веб-сервером, который передаёт данные о состоянии подключённого оборудования и внутренних переменных.
Тут нужно помнить, что это только «концептуальный» и базовый пример такого взаимодействия, максимально упрощённый для лучшего понимания начинающими сути самой технологии. Когда вы поймёте принцип, то далее сможете как угодно улучшать и модернизировать этот код. Например, уделить внимание его быстродействию и безопасности.
При помощи небольшой модификации HTML и JavaScript кода в скетче Arduino из предыдущей части этого руководства, можно заставить веб-сервер автоматически обновлять статус кнопки на веб-странице. Ручное инициирование AJAX запросов, которое использовалось в предыдущей части, больше не нужно.
Прежде чем продолжить знакомство с этой частью, вам нужно пройти предыдущую часть руководства и понять как работают AJAX запросы.
В следующем видеоролике показано, как веб-сервер Arduino автоматически обновляет состояние кнопки с помощью AJAX.
❯ Скетч AJAX веб-сервера Arduino
Используйте то же оборудование, что и в предыдущей части этого руководства:
- Контроллер Arduino Uno
- Плата Ethernet Shield
- Кнопка
- Резистор 10 кОм
- Соединительные провода
Кнопка подключается к плате Arduino/Ethernet Shield так, как показано на принципиальной схеме ниже. В изначальном состоянии вывод D3 контроллера подтянут к земле при помощи резистора 10 кОм (низкий потенциал, LOW или «0»), а после нажатия кнопки на вывод D3 подаётся высокий потенциал (HIGH или «1»).

В скетч eth_websrv_AJAX_switch из предыдущего урока нужно внести всего три изменения, чтобы автоматизировать AJAX вызовы, которые обновляют состояние кнопки на веб-странице.
Модифицированный скетч:
/*-------------------------------------------------------------- Скетч: eth_websrv_AJAX_switch_auto Описание: Arduino веб-сервер, отображающий состояние кнопки на веб-странице при помощи AJAX. Состояние кнопки обновляется автоматически. Оборудование: контроллер Arduino Uno, плата Ethernet Shield, кнопка. Программное обеспечение: среда разработки Arduino IDE Ссылки: - WebServer example by David A. Mellis and modified by Tom Igoe - Ethernet library documentation: http://arduino.cc/en/Reference/Ethernet - Learning PHP, MySQL & JavaScript by Robin Nixon, O'Reilly publishers Дата создания: 13 февраля 2013 Автор: W.A. Smith, http://startingelectronics.org --------------------------------------------------------------*/ #include <SPI.h> #include <Ethernet.h> byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(10, 0, 0, 20); // IP-адрес (нужно изменить на актуальный для вашей сети) EthernetServer server(80); String HTTP_req; // для хранения HTTP запроса void setup() { Ethernet.begin(mac, ip); server.begin(); Serial.begin(115200); pinMode(3, INPUT); // кнопка подключена к плате Arduino на пин D3 } void loop() { EthernetClient client = server.available(); if (client) { // got client? boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); // получаем очередной байт (символ) от клиента HTTP_req += c; // сохраняем символ HTTP запроса if (c == '\n' && currentLineIsBlank) { // Посылаем http заголовок client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: keep-alive"); client.println(); if (HTTP_req.indexOf("ajax_switch") > -1) { // AJAX запрос состояния кнопки GetSwitchState(client); } else { // Посылка веб-страницы, содержащей JavaScript код и AJAX вызовы client.println("<!DOCTYPE html>"); client.println("<html>"); // Заголовок веб-страницы и встроенный в неё код JavaScript client.println("<head>"); client.println("<title>Arduino Web Page</title>"); client.println("<script>"); client.println("function GetSwitchState() {"); client.println("nocache = \"&nocache=\"\ + Math.random() * 1000000;"); client.println("var request = new XMLHttpRequest();"); client.println("request.onreadystatechange = function() {"); client.println("if (this.readyState == 4) {"); client.println("if (this.status == 200) {"); client.println("if (this.responseText != null) {"); client.println("document.getElementById(\"switch_txt\")\ .innerHTML = this.responseText;"); client.println("}}}}"); client.println( "request.open(\"GET\", \"ajax_switch\" + nocache, true);"); client.println("request.send(null);"); client.println("setTimeout('GetSwitchState()', 1000);"); client.println("}"); client.println("</script>"); client.println("</head>"); // Тело веб-страницы client.println("<body onload=\"GetSwitchState()\">"); client.println("<h1>Arduino AJAX Switch Status</h1>"); client.println( "<p id=\"switch_txt\">Switch state: Not requested...</p>"); client.println("</body>"); client.println("</html>"); } // Выводим принятый HTTP запрос в Serial Serial.print(HTTP_req); HTTP_req = ""; // очищаем строку запроса 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) } // loop // Посылка данных о состоянии кнопки браузеру void GetSwitchState(EthernetClient cl) { if (digitalRead(3)) { cl.println("Switch state: ON"); } else { cl.println("Switch state: OFF"); } }
Изменения в HTML и JavaScript коде
Ниже показаны изменения, внесенные в HTML файл, который скетч Arduino отправляет в веб-браузер (этот файл отправляется построчно с помощью функции client.println() в скетче).

Модифицированный код веб-страницы для работы автоматических AJAX запросов.
Код кнопки веб-страницы
Во-первых, удаляется код, который создает кнопку на веб-странице, поскольку эта кнопка больше не нужна. На изображении выше он закомментирован.
Вызов функции GetSwitchState()
Функция GetSwitchState(), которая раньше вызывалась при нажатии кнопки на веб-странице, теперь автоматически вызывается при загрузке страницы. Это достигается добавлением её вызова в тег body (<body onload=«GetSwitchState()»>).
Примечание переводчика: здесь речь идёт о JavaScript функции GetSwitchState(), а не об одноимённой Arduino функции, которая занимается определением состояния кнопки, подключённой к серверу.
Эта строка добавляется в HTML код веб-страницы при помощи вызова следующей функции:
client.println("<body onload=\"GetSwitchState()\">");
Ежесекундные AJAX вызовы
Если мы не предпримем специальных действий и не изменим код для осуществления периодических вызовов, функция GetSwitchState() будет вызвана только один раз при загрузке веб-страницы.
Следующая строка кода добавляется в конец функции GetSwitchState(), чтобы эта функция автоматически вызывалась каждую секунду:
setTimeout('GetSwitchState()', 1000);
Эта строка JavaScript кода вызывает функцию GetSwitchState() (саму себя) каждые 1000 миллисекунд (каждую секунду). Таким образом каждую секунду выполняется AJAX запрос, который получает информацию о состоянии кнопки и обновляет её на веб-странице.
Этот код добавляется на веб-страницу при помощи следующей строки в Arduino скетче:
client.println("setTimeout('GetSwitchState()', 1000);");
❯ От переводчика о 6-й части
Если в двух словах резюмировать произведённые автором руководства улучшения предыдущего скетча, то он просто добавил на страницу JavaScript код, который автоматически раз в секунду вызывает функцию GetSwitchState(), которая, в свою очередь, автоматически, без участия пользователя, производит AJAX запросы к Arduino серверу.
В результате мы получаем динамическую систему, которая «сама» обновляет данные на веб-странице и делает это без каких-либо видимых артефактов.
Этот пример реализует однонаправленную передачу информации (о состоянии кнопки) сервер — клиент, если сюда добавить ещё и передачу (пользовательских) данных от клиента к серверу, то мы получим полностью интерактивную и двунаправленную систему.
Часть 1, часть 2, часть 3, часть 4, часть 5.

