Нарядный Arduino вэб–сервер с мишурой. Обезболивающее.

[ Версия для печати ]
Добавить в Telegram Добавить в Twitter Добавить в Вконтакте Добавить в Одноклассники
Страницы: (2) [1] 2   К последнему непрочитанному [ ОТВЕТИТЬ ] [ НОВАЯ ТЕМА ]
Aberrant
26.11.2023 - 06:03
Статус: Offline


На фоксе! Всегда!

Регистрация: 3.10.20
Сообщений: 3542
45
Осторожно! Чтение данного текста вслух может вызвать адского сотону.
Только для красноглазых!



Мой приятель приболел, а т.к. переизбыток свободного времени вызывает у него зуд в разных частях тела, он начал мучить свою Arduino Uno R3.

Железка довольно архаичная, а потому быстро приземлила его сообщением о том, что все 2 килобайта оперативной памяти закончились.
*сюрпрайз мазафака!

Приятель не сдался — он отправил мне скетч и попросил "сделай мне нарядно, а?"

Я (ленивый, да ещё и гуманитарий) тут же принялся писать ему ответ в духе: ну вот же, первая же ссылка в гугле, тебя там, что, забанили?...
Допечатав ещё несколько нелестных высказываний в адрес форточников, аникейщиквов и прочих мышкоелозителей, я полез гуглить.
А вот фигушки!
Мой шикарный план "отделаться ссылкой на какое-нибудь обсуждение или урок" провалился с треском!
Гугл вместе яндексом упорно выдавали мне всякую дичь и вообще не про то, что нужно было бы "по науке".

Задача то на самом деле тривиальная:
на Arduino Uno R3 у которой есть пара сенсоров и пара актуаторов, есть RTC и сетевуха W5500 (классная штука, OSI L4 уже в кремне и не напрягает атмегу!),
крутится вэб–сервер, который не выглядит "нарядно",
т.е. нет у него своих иконок (favicon) и приличного оформления (CSS), а очень хочется.

И вот тут он затронул проблему, которая давно медным тазом накрывает интернет,
а именно: десигнеры, которые с трудом освоили тильду конечно же знают и такой вещи, как favicon
и конечно же они знают, что под разные браузеры на разных устройствах эти самые иконки нужны разных размеров,
но не знают "как и зачем",
а потому упорно копируют чужие заблуждения и ошибки.

Т.е. если делать "нарядно" по–дизайнерски, то конечно же придётся к ардуинке подцеплять flash–модуль с карточкой на 64Gb.
*PROGMEM на ATmega328 всего 32Kb

А ещё же хочется красивую вёрстку (собственно именно на этом этапе у приятеля и закончилась оперативка),
да чтобы с всеобъемлющим CSS, а там и JS захочется побольше... Чтобы всё как у больших.

Но вернёмся к favicon и дизайнерам.
Если открыть исходники странички на которой ты читаешь этот текст (Ctrl+U), то увидишь, что в команде ЯПа тоже есть десигнер, который вообще не вдупляет что он творит.

Давай на примере самого тупого в плане работы с favcion браузера (из актуальных на данный момент) — Chrome (любой на движке хрома)
*пока ты ещё не дочитал до развязки — ты сейчас думаешь про PNG 16x16px с именем favicon.ico?
бггг!


Если ты открыл исходный текст этого документа, то может быть даже обратил внимание, что значки вкладок отличаются (вкладка с исходниками от вкладки документа).
Понял что произошло, да?
Я подтвержу твои догадки: при открытии сайта в браузере, подгружается одна из favicon описанных в <head/>,
причём браузер сам выбирает какую именно загрузить.
Chrome сейчас для тебя выбрал иконку favicon-32x32.png и конечно же сжал её до 16x16px (на обычном 1080p десктопе с Windows),
но для вкладки с исходниками тот же Chrome показал иконку favicon.ico — и тут всё ясно: браузер не выполнял инструкции из <head/>, а просто самовольно спросил у сервера файл /favicon.ico
*а ты думал откуда в логах твоего сервера так много обращений по этому URL?

Бред! А ведь там ещё иконки для андроида, для всяких яблок и для тёмной темы оформления браузера.
*Интересно — для какого браузера ЯП объявил favicon.ico в <head/>?
Огнелис у ЯПа вообще спросил favicon-16x16.png и favicon-194x194.png — бля, да что происходит то?


И что, нам теперь так же делать на ардуинке — каждому браузеру по иконке рисовать?

Нет конечно.

Универсальное обезболивающее давно изобретено — SVG!
В отличии от растровых форматов, векторные изображения превосходно масштабируются,
а значит нам нужно всего одно изображение на все случаи жизни (ну, может два — иногда не обойтись без версии "для тёмной темы")

Объяви в <head/> один единственный favicon.svg, достаточно крупный, чтобы не выглядел убого при большом масштабе и пусть браузеры и пр. сами себе выбирают нужный размер.

Большинство вменяемых верстальщиков об этом знают давно и успешно пользуются,
но оказывается, что готовые примеры реализации SVG favicon для Aurduino вообще не гуглятся.
Вместо этого начинающему МК`шнику упорно предлагается подключить к Arduino flash–модуль, хранить там картинку или переписать блоб в BASE64 и хранить это всё в виде стрингов.

Придётся перебороть лень и сделать "правильно", а заодно показать "любителю нарядного" как не просрать всю оперативку.

сразу же отмазка (AKA Disclaimer): в первую очередь делюсь с тобой потому, что сам не нашёл готового решения,
ну и воспринимай прочитанное критично, это не единственное расово–верное решение — сам я нередко ошибаюсь и заблуждаюсь.


1. Мы объявим только одну иконку в <head/>,
в теории браузер не должен в обычных условиях спрашивать ардуинку на предмет /favicon.ico,
но на всякий случай по этому URL`у нужно поставить заглушку.
Самая подходящая заглушка, ИМХО, это вернуть код 204 (no content) — это и не ошибка, и не предупреждение, а значит для всех "всё идёт по плану".
Кстати, рекомендую на твоём сайте сделать тоже самое — это избавит тебя от засирания логов предупреждениями о 404
(ты же наверное отдаёшь красивую 404.php — не дофига ли трафика ради того, чтобы сказать браузеру или боту о том, что такой иконки нет?)
и тем самым облегчит чтение логов, ну и сэкономит какое-то количество места в /var/log/

2. Попутно придётся решить проблему с нехваткой оперативной памяти.
Я ленив, а значит буду использовать стандартную библиотеку StreamLib (довольно лёгкая, но сэкономит время и нервы).
Но ты можешь наплевать на побайтовый вывод из PROGMEM и пользоваться "чистым" F() macro (включи сетевой сниффер,
посчитай количество переданных пакетов на страничку с показаниями сенсоров и парой выключателей — бодрит?
)
Или же можешь самостоятельно читать в буфер и отправлять фреймы при его наполнении.
Не? Я так и подумал ;)

Постараюсь объяснить подробно что и для чего, но ты на меня не обижайся — это только для тех, кто вообще ничего не понимает, ага?
И да, я не смогу ответить тебе в этом топике — из–за болезненной реакции на человеческую глупость, я выпросил себе лимит "одно сообщение в сутки".

Погнали:

подключаем сетевуху W5500 и функции вэб–сервера
Код
#include <SPI.h>
#include <Ethernet.h>

объявляем размер буфера для StreamLib ну и саму библиотеку цепляем
Код
const size_t RESPONSE_BUFFER_SIZE = 64;
#include <StreamLib.h>

настраиваем сетевуху
Код
byte mac[] = { 0x00, 0x22, 0x06, 0xAA, 0xAB, 0xAC };  //  пасхалочка;)
IPAddress ip(10, 0, 0, 5);
EthernetServer server(80);

запускаем весь фарш
Код
void setup() {
 Ethernet.begin(mac, ip);
 server.begin();
}

Код
void loop() {
 String HTTP_req; // строка в которую будем сохранять заголовки от браузера для отлова URL`ов. В каждом витке она будет обнуляться, а значит оперативка не вытечет вся через 3-4 итерации

// тут всё как у всех, ничего нового, это фишки из Ethernet.h — проверки готовности самой либы и того, что браузер и сервер в данный момент в адеквате.
 EthernetClient client = server.available();
 if (client) {

   boolean currentLineIsBlank = true;
   while (client.connected()) {
     if (client.available()) {

// пнём StreamLib, чтобы уже был готов новый буфер на каждый виток
       char buffer[RESPONSE_BUFFER_SIZE];
       BufferedPrint response(client, buffer, sizeof(buffer));

// читаем HTTP–запрос от браузера в "c" и складываем его в строку HTTP_req, чтобы потом узнать чего от нас хочет браузер на этом витке
       char c = client.read();
       HTTP_req += c;

// если барузер закончил свой запрос пустой строкой, то вступаем...
       if (c == '\n' && currentLineIsBlank) {

// поймали в HTTP_req "GET / ", значит отдадим браузеру тело странички
         if (HTTP_req.startsWith("GET / ")) {
// подстелил соломку на предмет кодировки, добавил хоть какую–то вёрстку, чтобы было видно, что буфер работает.
// тут же, в <head/> указываем ссылки на иконку и CSS — их браузер спросит на двух следующих витках
// да, тут используется F() macro для записи всего этого в PROGMEM, но читать будем уже в буфер через "response", а значит ничего страшного, просто "не изобретаем велосипед"
           response.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: keep-alive\r\n\r\n"
                            "<!DOCTYPE html><html lang=\"ru\"><head><meta charset=\"utf-8\"/><link rel=\"stylesheet\" type=\"text/css\" href=\"a.css\"/>"
                            "<title>Decorative #0000FF board with favicon</title><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>"
                            "<link rel=\"icon\" href=\"/favicon.svg\" type=\"image/svg+xml\"/></head><body>"
                            "<header><h1>Нарядная #0000FF доска с красным квадратом</h1></header></body><html>"));
           response.flush(); // очищаем буфер!
         }

// что-то пошло не так и мы всё же поймали запрос на favicon.ico, тогда отдадим 204 no content и не паримся.
         if (HTTP_req.startsWith("GET /favicon.ico")) {
           response.print(F("HTTP/1.0 204 no content\r\n"));
           response.flush(); // очищаем буфер!
         }

// поймали запрос на иконку в векторе. я нарисовал красный квадрат, а яндекс рекомендовал сделать его сразу большим, аж 120x120px — вектору пофигу, что через 50ms его сожмут до 16x16
         if (HTTP_req.startsWith("GET /favicon.svg")) {
           response.print(F("HTTP/1.1 200 OK\r\nContent-Type: image/svg+xml\r\nConnection: keep-alive\r\n\r\n"
                            "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg width=\"120\" height=\"120\" xmlns=\"http://www.w3.org/2000/svg\">"
                            "<rect fill=\"#f00\" width=\"100\" height=\"100\" x=\"10\" y=\"10\"/></svg>"));
           response.flush(); // очищаем буфер!
         }

// поймали запрос на CSS — ну, написал что–то для веса
         if (HTTP_req.startsWith("GET /a.css")) {
           response.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/css\r\nConnection: keep-alive\r\n\r\n"
                            "*{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto;font-size:18px;color:#333;text-decoration:none}"
                            "body{width:100%;min-height:100vh;display:grid;place-items:center}header h1{font-size:180%;color:#000;font-weight:400}"));
           response.flush(); // очищаем буфер!
         }
         break; // закончили на текущем витке
       }
// стандартная для Ethernet.h фишка по отлову пустой строки — это нужно, чтобы знать о том, что браузер закончил передавать HTTP–заголовок
       if (c == '\n') {
         currentLineIsBlank = true;
       } else if (c != '\r') {
         currentLineIsBlank = false;
       }
     }
   }
   delay(1); // редко случается, но всё же иногда браузеру нужна хотя бы 1ms дополнительно в промежутке между запросом и ответом
   client.stop();
 }
}

без комментариев для удобства восприятия:
Код
#include <SPI.h>
#include <Ethernet.h>

const size_t RESPONSE_BUFFER_SIZE = 64;
#include <StreamLib.h>

byte mac[] = { 0x00, 0x22, 0x06, 0xAA, 0xAB, 0xAC };
IPAddress ip(10, 0, 0, 5);
EthernetServer server(80);

void setup() {
 Ethernet.begin(mac, ip);
 server.begin();
}

void loop() {
 String HTTP_req;
 EthernetClient client = server.available();
 if (client) {

   boolean currentLineIsBlank = true;
   while (client.connected()) {
     if (client.available()) {

       char buffer[RESPONSE_BUFFER_SIZE];
       BufferedPrint response(client, buffer, sizeof(buffer));
       char c = client.read();
       HTTP_req += c;
       if (c == '\n' && currentLineIsBlank) {

         if (HTTP_req.startsWith("GET / ")) {
           response.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: keep-alive\r\n\r\n"
                            "<!DOCTYPE html><html lang=\"ru\"><head><meta charset=\"utf-8\"/><link rel=\"stylesheet\" type=\"text/css\" href=\"a.css\"/>"
                            "<title>Decorative #0000FF board with favicon</title><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>"
                            "<link rel=\"icon\" href=\"/favicon.svg\" type=\"image/svg+xml\"/></head><body>"
                            "<header><h1>Нарядная #0000FF доска с красным квадратом</h1></header></body><html>"));
           response.flush();
         }

         if (HTTP_req.startsWith("GET /favicon.ico")) {
           response.print(F("HTTP/1.0 204 no content\r\n"));
           response.flush();
         }

         if (HTTP_req.startsWith("GET /favicon.svg")) {
           response.print(F("HTTP/1.1 200 OK\r\nContent-Type: image/svg+xml\r\nConnection: keep-alive\r\n\r\n"
                            "<?xml version=\"1.0\" encoding=\"UTF-8\"?><svg width=\"120\" height=\"120\" xmlns=\"http://www.w3.org/2000/svg\">"
                            "<rect fill=\"#f00\" width=\"100\" height=\"100\" x=\"10\" y=\"10\"/></svg>"));
           response.flush();
         }

         if (HTTP_req.startsWith("GET /a.css")) {
           response.print(F("HTTP/1.1 200 OK\r\nContent-Type: text/css\r\nConnection: keep-alive\r\n\r\n"
                            "*{margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto;font-size:18px;color:#333;text-decoration:none}"
                            "body{width:100%;min-height:100vh;display:grid;place-items:center}header h1{font-size:180%;color:#000;font-weight:400}"));
           response.flush();
         }
         break;
       }
       if (c == '\n') {
         currentLineIsBlank = true;
       } else if (c != '\r') {
         currentLineIsBlank = false;
       }
     }
   }
   delay(1);
   client.stop();
 }
}
Тэги: #arduino
 
[^]
Yap
[x]



Продам слона

Регистрация: 10.12.04
Сообщений: 1488
 
[^]
4burator
26.11.2023 - 06:06
24
Статус: Offline


Балагур

Регистрация: 11.01.20
Сообщений: 918
ТС! Ты сайтом не ушибся? biggrin.gif
 
[^]
Aleva
26.11.2023 - 06:07
18
Статус: Offline


Приколист

Регистрация: 25.04.14
Сообщений: 291
Ебать колотить,кто здесь? blink.gif
 
[^]
WestZ
26.11.2023 - 06:09
9
Статус: Offline


Ярила

Регистрация: 3.09.23
Сообщений: 1251


Размещено через приложение ЯПлакалъ

Нарядный Arduino вэб–сервер с мишурой. Обезболивающее.
 
[^]
Ухаха
26.11.2023 - 06:09
5
Статус: Offline


Ярила

Регистрация: 8.07.22
Сообщений: 1046
Ух ты, и это в 6 утра воскресения, когда глаза красные совсем от другого

Размещено через приложение ЯПлакалъ
 
[^]
4burator
26.11.2023 - 06:12
2
Статус: Offline


Балагур

Регистрация: 11.01.20
Сообщений: 918
Цитата (Ухаха @ 26.11.2023 - 10:09)
Ух ты, и это в 6 утра воскресения, когда глаза красные совсем от другого

О работе думал и плакал? cool.gif

Это сообщение отредактировал 4burator - 26.11.2023 - 06:17
 
[^]
DeFrag49
26.11.2023 - 06:12
-2
Статус: Offline


Юморист

Регистрация: 8.07.17
Сообщений: 457
delay(1);
Что это за диЩьььь?

Заголовочник delay.h не подключен! Переменная delay прописывается delay_ms(10); (типа 10 мсек)

Компилятор залупится через 0,0000001 сек после попытки компиляции %)))

Размещено через приложение ЯПлакалъ
 
[^]
DeFrag49
26.11.2023 - 06:14
3
Статус: Offline


Юморист

Регистрация: 8.07.17
Сообщений: 457
Плюсик поставил, на всяк случай. За старания %)
Но всё равно куйня. Переделывай %)))

Размещено через приложение ЯПлакалъ
 
[^]
Жангиз
26.11.2023 - 06:15
4
Статус: Offline


Ярила

Регистрация: 9.10.17
Сообщений: 1499
Подошёл к зеркалу, глянул-глаза стального цвета-две недели во рту сухо.
Не, читать не стану.
 
[^]
Бошк
26.11.2023 - 06:16
2
Статус: Offline


Балагур

Регистрация: 6.11.07
Сообщений: 951
Интересно. С удовольствием прочитал, и даже всё понял. Но зачем на ЯПъ то? IXBT там,или ещё куда в профильное?
 
[^]
altcms
26.11.2023 - 06:18
3
Статус: Offline


Старый байкер

Регистрация: 23.06.12
Сообщений: 848
Цитата (Aberrant @ 26.11.2023 - 10:03)
Я (ленивый, да ещё и  гуманитарий) тут же принялся писать ему ответ в духе: ну вот же, первая же ссылка в гугле, тебя там, что, забанили?...

Мог бы и ссылкой отделаться и нам мозг с утра не грузить https://hi-lab.ru/arduino-mega-server/details/screenshots Всё давно придумано и написано.

Взять что то на ESP8266 ,будет дешевле Uno R3 и не будет кривого как моя жизнь W5500, и памяти хватит. А на Uno R3 что то примитивное сделать и то памяти мало.

Это сообщение отредактировал altcms - 26.11.2023 - 06:26
 
[^]
00eugene00
26.11.2023 - 06:20
6
Статус: Offline


Ярила

Регистрация: 5.10.13
Сообщений: 4324
Никуя! ТС с козырей зашел в воскресенье.
 
[^]
ezhiknsk
26.11.2023 - 06:22
1
Статус: Offline


-

Регистрация: 26.07.14
Сообщений: 345
Ловите наркомана!!!
 
[^]
alex1506
26.11.2023 - 06:26
0
Статус: Offline


Ярила

Регистрация: 3.08.16
Сообщений: 8534
Цитата (altcms @ 26.11.2023 - 06:18)
Мог бы и ссылкой отделаться и нам мозг с утра не грузить https://hi-lab.ru/arduino-mega-server/details/screenshots Всё давно придумано и написано.

Вроде у ТС Uno былизначально.

Размещено через приложение ЯПлакалъ
 
[^]
mnr1
26.11.2023 - 06:29
0
Статус: Offline


Ярила

Регистрация: 9.07.13
Сообщений: 5933
тоже что-ли умное что-нибудь написать? :)
 
[^]
altcms
26.11.2023 - 06:29
-1
Статус: Offline


Старый байкер

Регистрация: 23.06.12
Сообщений: 848
Цитата (alex1506 @ 26.11.2023 - 10:26)
Цитата (altcms @ 26.11.2023 - 06:18)
Мог бы и ссылкой отделаться и нам мозг с утра не грузить https://hi-lab.ru/arduino-mega-server/details/screenshots Всё давно придумано и написано.

Вроде у ТС Uno былизначально.

Я уже подписал чтоб поменял на ESP и выкинул постоянно подвисающий W5500. Мало памяти на uno чтоб всё локально сделать, только что то примитивное. Мегу и дуо не предлагаю там ценник конячий для такой поделки выходит.
 
[^]
Тутанахламон
26.11.2023 - 06:32
3
Статус: Offline


Весельчак

Регистрация: 3.10.18
Сообщений: 188
А я прочитал на всякий случай. С ардуиной не работал, но видел и в руках держал... smile.gif
 
[^]
OldGarry
26.11.2023 - 06:45
0
Статус: Offline


Хуй! Пизда! Социализм!

Регистрация: 19.06.12
Сообщений: 3199
Опохмелись штоль...
 
[^]
HAARP
26.11.2023 - 07:00
3
Статус: Offline


Шаман

Регистрация: 25.03.12
Сообщений: 7397
Само то для утра воскресенья! Бодрит! И понимаешь , что кто-то совсем не деградирует и в то же время понимаешь , что есть ещё куда расти самому себе.
Ещё не освоена высшая математика ( а значит ждём топик от квантовых физиков)

Размещено через приложение ЯПлакалъ
 
[^]
kazakD
26.11.2023 - 07:09
1
Статус: Offline


Старый зануда

Регистрация: 1.09.20
Сообщений: 260
Это канал про аниме?
Да
А как пропатчить KDE под FreeBSD?

Размещено через приложение ЯПлакалъ
 
[^]
altcms
26.11.2023 - 07:33
3
Статус: Offline


Старый байкер

Регистрация: 23.06.12
Сообщений: 848
Вот когда такое читаю (так как сам в этом копался), возникает сразу вопрос, зачем брать что есть а не то что надо. Ну вот на этом примере, есть uno и W5500. Первая проблема, при отключении питания сеть не поднимается, берём паяльник начинаем дорабатывать, повесили сопротивление стало лучше, начинается писанина, опа памяти мало, начинается навешивание памяти , а пины то на uno не бесконечные, и тут возникает вопрос куда датчики вешать, исполнительные устройства да ещё и желательно локальное управление сделать и индикацию, Пины тают как весенний снег. Начинаем заюзывать i2c, замечательно, и вдруг прерываний не хватает, Ну вот вроде всё победили и сделали а web интерфес тормозит, а охото чтоб всё в реальном времени обновлялось, и опять упираемся в память и скорость работы ардуинки. А потом начинают считать сколько в железо ввалено в труды и времени и глаза округляются. Может стоит сразу железо под задачу подбирать ?

И да сперва функционал пишут, а потом уже бантики, А тот я понял по описаню пары сенсоров и актуаторов это на теплице форточками хлопать :) Серва это сделать надо.

Это сообщение отредактировал altcms - 26.11.2023 - 08:02
 
[^]
TTYL
26.11.2023 - 08:26
3
Статус: Online


Шутник

Регистрация: 16.02.19
Сообщений: 25


Размещено через приложение ЯПлакалъ

Нарядный Arduino вэб–сервер с мишурой. Обезболивающее.
 
[^]
ПетяСискин
26.11.2023 - 08:39
1
Статус: Offline


Гость

Регистрация: 3.02.15
Сообщений: 339
Прочитал. Допил всё что было. Не хватило. Нужна срочно добавка, а до 11 ещё далеко. Сука.......
 
[^]
ra3tst
26.11.2023 - 08:46
0
Статус: Offline


Ярила

Регистрация: 10.07.14
Сообщений: 1481
Кодят кто? Индийцы. ТС, ты индиец?
 
[^]
Varhar
26.11.2023 - 08:50
1
Статус: Offline


Ярила

Регистрация: 26.10.14
Сообщений: 3059
Захватывающе.
Прочитал с огромным интересом, благодарю.
 
[^]
Понравился пост? Еще больше интересного в Телеграм-канале ЯПлакалъ!
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии. Авторизуйтесь, пожалуйста, или зарегистрируйтесь, если не зарегистрированы.
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) Просмотры темы: 3840
0 Пользователей:
Страницы: (2) [1] 2  [ ОТВЕТИТЬ ] [ НОВАЯ ТЕМА ]


 
 



Активные темы






Наверх