Ajax web-server (w5500)
- Войдите на сайт для отправки комментариев
Здравствуйте.
В перспективе создать web-сервер с выводом показаний датчиков и возможностью вкл/выкл нагрузок.
В статике вывод аналоговых и цифровых показателей работает, кноки управления нагрузки тоже. Изучаю Ajax. Победить его на ENC28J60 без SD не смог. Приобрел w5500.
Скетч из примера в сети с подставленным PIR-сенсором:
[spoiler]
#include <SPI.h> #include <Ethernet.h> // MAC address from Ethernet shield sticker under board byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 1, 177); // IP address, may need to change depending on network EthernetServer server(80); // create a server at port 80 String HTTP_req; // stores the HTTP request int pirPin = 2; // инициализируем пин для получения сигнала от пироэлектрического датчика движения void setup() { Ethernet.begin(mac, ip); // initialize Ethernet device server.begin(); // start to listen for clients Serial.begin(9600); // for diagnostics pinMode(2, INPUT); // switch is attached to Arduino pin 3 } void loop() { EthernetClient client = server.available(); // опрашиваем канал в поисках клиента if (client) { // got client? boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { // client data available to read char c = client.read(); // read 1 byte (character) from client HTTP_req += c; // save the HTTP request 1 char at a time // last line of client request is blank and ends with \n // respond to client only after last line received if (c == '\n' && currentLineIsBlank) { // send a standard http response header 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 request for switch state // read switch state and send appropriate paragraph text GetSwitchState(client); } else { // HTTP request for web page // send web page - contains JavaScript with AJAX calls client.println("<!DOCTYPE html>"); client.println("<html>"); 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(\"data_to_update\").innerHTML = this.responseText;"); client.println("}}}}"); client.println("request.open(\"GET\", \"ajax_switch\" + nocache, true);"); client.println("request.send(null);"); client.println("setTimeout('GetSwitchState()', 1000);"); // интервал запросов данных (вызова функции "GetSwitchState()") (мсек) client.println("}"); client.println("</script>"); client.println("</head>"); client.println("<body>"); client.println("<body onload=\"GetSwitchState()\">"); client.println("<h1>Arduino AJAX Switch Status</h1>"); client.println("<div id=\"data_to_update\">"); client.print("<p id=\"switch_txt\">Switch state: Not requested...</p>"); // switch state and button code will be inserted here by the JavaScript after AJAX call client.println("</div>"); client.println("</body>"); client.println("</html>"); } Serial.print(HTTP_req); // display received HTTP request on serial port HTTP_req = ""; // finished with request, empty string break; } //каждая строка полученная от клиента заканчивается \r\n 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) } // send the state of the switch to the web browser void GetSwitchState(EthernetClient cl) { if (digitalRead(2)) { cl.println("<p>Switch state: ON</p><button type=\"button\" style=\"color: green;\" onclick=\"GetSwitchState()\">On</button>"); } else { cl.println("<p>Switch state: OFF</p><button type=\"button\" style=\"color: red;\" onclick=\"GetSwitchState()\">Off</button>"); } }
[/spoiler]
Вопрос: После загрузки скетча страница отображает/обновляет статус датчика, xml ходят. Но стоит только перезагрузить страницу в браузере, статус показаний меняется на "Not requested...". Тоже самое и в других браузерах. Грубо говоря всё работает только при первой загрузке страницы сразу после заливки скетча. Выглядит это примерно так:
Подскажите как мне получать статус с датчиков после перезагрузки страницы?
А что терминал прилетает? есть там строка "ajax_switch"?
Похоже не весь ответ считывает.
и замени в строке 28,
if
наwhile.
Можно в консоль браузера статусы хттп-реквестов повыводить - мошт ошибка возникает при загрузке. А весь html вынести в PGM и выплёвывать одной строкой, не ломая мозг...
1. Гонять по TCP/IP HTML код тупо и небезопасно. Конечно, в домашней сети его не подменить, но привыкать к этому не следует. Не всяк тот хакер. Хак - код дебила, индусский и т. п., существуют правила. Любой хак однажды аукается. Код должен предусматривать все состояния, и не быть полиморфным. И нельзя писать код который работает, надо писать код который понятен. Иначе есть риск стать индусом, спать на улице, начать поклоняться Шиве и подцепить паразитов. Прекратите в ответах выдавать HTML. Для состояний есть JSON. И короче, BTW.
2. Раз уж такой праздник (Wiznet), можно же править заголовки. То есть ещё раз тыкаю носом: перепишите JS так чтобы ему был нужен только JSON: "[0]" выключено, "[1]" включено, без кавычек (в строке), через запятую если несколько. На ENC28J60 заголовки тоже можно изменять, держу в курсе (правда, треба уже лезть в библиотеку, там это спрятано).
3. Мне лень предусматривать различные запросы на дуине, я просто отдаю полезный JSON, добавив заголовок "Access-Control-Allow-Origin: *" (без кавычек), а сам вебинтерфейс (HTML+JS) держу на клиенте. От флешки смартфона, если записать туда полуторакилобайтный HTML файл, не убавится. А писанины меньше.
4. Недоступность ресурса после перезагрузки значит только одно: цикл обслуживания Eth - кривой. Сверяйте с примером.
5. Убедиться в наличии заголовка "Connection: close" (без кавычек). Соединения keep-alive чреваты вывертами.
Верно. Но чем боротся с багами от применения старого громоздкого барахла из кладовки вебдизайна просто применить протокол, адекватный для реалтайм данных - https://ru.wikipedia.org/wiki/WebSocket
Правильно ли я понимаю, что Voodoo предлагает сам код страницы с интерфейсом помещать вручную на каждый смартфон или планшет (предварительно произведя Jailbreak для определённых), JSON применять в виде "...{"states":"0,1,1,1,1,0"}..." для дополнительно написанного JS-парсера, бояться keep-alive соединений и править некие тайные заголовки, зачем-то спрятанные внутри библиотеки? В противном случае же Шива наградит пейсателя вшами, а Ганеш заставит петь и танцевать до изнеможения.
По поводу кривизны обслуживания запросов - согласен.
Не, неправильно. Не надо никаких парсеров, всё есть в V8.
Насчёт вставить HTML в progmem и отдавать вместе со статусом: слушаю и записываю. А то любят такие "ой да ты нуб, вот есть такая то магия, я ваще фаерболы суммоню". А как кастануть эту магию попросишь - так все врассыпную, как боты от перса, когда на паузу поставишь, читы подрубишь и левел апнешь.
Я на дваче и пр. не сижу, поэтому жаргон мне этот непонятен. А ролики с кликбейтными названиям вообще не смотрю.
Но, если действительно интересует, как в PGM держать исходник страницы, не размазывая его по куче print() то изволь:
После этого достаточно просто на ПК всё отладить и копипастнуть исходник страницы прямо в .ino файл.
Что же касается V8... Тебе, конечно, это может показаться странным, но я из Safari смотрю интерфейс, а то и из Firefox. Поэтому предпочитаю использовать функционал объекта JSON, который есть там и сям и кормить его вполне легальным (хотя и избыточным) JSON-форматом без извращений с псевдокомпрессией. И при этом мне не приходится ломать голову над тем, как на iPad засунуть html-файл, потом его загрузить из локального хранилища в единственный браузер, который имеет механику, чтобы раскрутить нечто, заточенное под V8.
Спасибо за ответы.
if
наwhile.
После этого действия web-страница в браузерах не загружается.
Стало намного стабильнее после замены библиотеки с Ethernet на Ethernet2 при том же скетче.
Logik Спасибо за наводку, начал изучать web сокет.
А давайте сначала по RS232 погоняем, а уж ПОТОМ...