Официальный сайт компании Arduino по адресу arduino.cc
ESP8266WebServer - server send()
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Вс, 04/03/2018 - 16:27
В Arduino IDE->Примеры->ESP8266WebServer есть скетч AdvancedWebServer.ino
#include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> #include <ESP8266mDNS.h> const char *ssid = "YourSSIDHere"; const char *password = "YourPSKHere"; ESP8266WebServer server ( 80 ); const int led = 13; void handleRoot() { digitalWrite ( led, 1 ); char temp[400]; int sec = millis() / 1000; int min = sec / 60; int hr = min / 60; snprintf ( temp, 400, "<html>\ <head>\ <meta http-equiv='refresh' content='5'/>\ <title>ESP8266 Demo</title>\ <style>\ body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\ </style>\ </head>\ <body>\ <h1>Hello from ESP8266!</h1>\ <p>Uptime: %02d:%02d:%02d</p>\ <img src=\"/test.svg\" />\ </body>\ </html>", hr, min % 60, sec % 60 ); server.send ( 200, "text/html", temp ); digitalWrite ( led, 0 ); } void handleNotFound() { digitalWrite ( led, 1 ); String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for ( uint8_t i = 0; i < server.args(); i++ ) { message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n"; } server.send ( 404, "text/plain", message ); digitalWrite ( led, 0 ); } void setup ( void ) { pinMode ( led, OUTPUT ); digitalWrite ( led, 0 ); Serial.begin ( 115200 ); WiFi.begin ( ssid, password ); Serial.println ( "" ); // Wait for connection while ( WiFi.status() != WL_CONNECTED ) { delay ( 500 ); Serial.print ( "." ); } Serial.println ( "" ); Serial.print ( "Connected to " ); Serial.println ( ssid ); Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() ); if ( MDNS.begin ( "esp8266" ) ) { Serial.println ( "MDNS responder started" ); } server.on ( "/", handleRoot ); server.on ( "/test.svg", drawGraph ); server.on ( "/inline", []() { server.send ( 200, "text/plain", "this works as well" ); } ); server.onNotFound ( handleNotFound ); server.begin(); Serial.println ( "HTTP server started" ); } void loop ( void ) { server.handleClient(); } void drawGraph() { String out = ""; char temp[100]; out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"150\">\n"; out += "<rect width=\"400\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n"; out += "<g stroke=\"black\">\n"; int y = rand() % 130; for (int x = 10; x < 390; x+= 10) { int y2 = rand() % 130; sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", x, 140 - y, x + 10, 140 - y2); out += temp; y = y2; } out += "</g>\n</svg>\n"; server.send ( 200, "image/svg+xml", out); }
Работает он прекрасно.
Но когда я в функции void drawGraph()
void drawGraph() { String out = ""; char temp[100]; out += "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"400\" height=\"150\">\n"; out += "<rect width=\"400\" height=\"150\" fill=\"rgb(250, 230, 210)\" stroke-width=\"1\" stroke=\"rgb(0, 0, 0)\" />\n"; out += "<g stroke=\"black\">\n"; int y = rand() % 130; for (int x = 10; x < 390; x+= 10) { int y2 = rand() % 130; sprintf(temp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" stroke-width=\"1\" />\n", x, 140 - y, x + 10, 140 - y2); out += temp; y = y2; } out += "</g>\n</svg>\n"; server.send ( 200, "image/svg+xml", out); }
определяю данные размером более 2500 байт ( char temp[2500]; ) и впоследствии сервер отправляет их в ответ на обращение к вебсерверу (server.send ( 200, "image/svg+xml", out);) - esp в этот момент крашиться.
При размере данных вплоть до ~2500 байт - esp не крашится.
В функции void drawGraph() я строю график на языке разметки svg, объем ~10кб
Подскажите, как правильно передавать такие объемы?
Код, который не работает секретен? Или почему не показали?
Думаю, что проблема с памятью. Попробуйте для начала избавиться от типа String. Тем более, от такого варванского его использования. Уверен, что поможет.
Вот код:
если еще увеличить размер temp1 и добавить строк - esp крашится.
Думаю, что проблема с памятью. Попробуйте для начала избавиться от типа String. Тем более, от такого варванского его использования. Уверен, что поможет.
Делаю как в примере - ни шага в сторону :)
Если на вывод идет текст - как же его пихать, если не как String?
Делаю как в примере - ни шага в сторону :)
Пример - он на то и пример, чтобы показать принцип, используя минимум строк кода. Кроме того, в примере работы с единственным устройством, как правило, ресурсов МК хватает с избытком, так что ради понятности кода эти ресурсы зачастую приносятся в жертву.
В реальном проекте оптимизировать следует по совсем иным принципам.
Если на вывод идет текст - как же его пихать, если не как String?
Вообще-то в Ардуино целесообразнее применять char*. Но если касается вывода - то выводить побайтно можно сообщения вообще неограниченной длины. Т.е. не надо ждать, пока накопится посылка целиком, либо составлять длинную строку из отдельных кусочков: каждый из ее фрагментов выводится побайтно один за другим. Расход ресурсов - 1 байт.
не победил этот snprintf и server.send но хотелось бы. если кто-то сможет подсказать - буду благодарен.
использую
Делаю как в примере - ни шага в сторону :)
Сомневаюсь.
Объект/класс String я не мучал, поэтому не знаю насколько корректно передавать вместо указателя на него - указатель на char* , а ведь в https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WebServer/src/ESP8266WebServer.h написано, что нет оверлоада функции send(), который принимал бы указатель на char[]... Однако там есть прекрасный вариант - send_P(), который позволяет засылать строку прямо с PROGMEM (наверняка).
Спасибо. Но за плечами у меня только программирование на паскале и ассемблере в школе (цать лет назад). Ниче не понял :-\
Видимо в моем случае костыли - наше все.
http://www.esp8266.com/viewtopic.php?f=29&t=2417 - в первом посте видите объявление с PROGMEM? Делайте такое же и .send_P(200, "image/svg+xml", имя_progmem_переменной_в_которой_лежит_svg_картинка);
Возможно, что всё будет ОК.
Что-то лыжи не едут...
Скопировал кусок кода, который приводит автор по ссылке и вставил в пустой скетч.
Данный код выдает ошибку "Ошибка компиляции для платы Generic ESP8266 Module"
Подробный текст ошибки (вдруг что-то полезное увидите):
Arduino: 1.8.5 (Windows 7), Плата:"Generic ESP8266 Module, 80 MHz, ck, 26 MHz, 40MHz, QIO, 512K (no SPIFFS), v2 Prebuilt (MSS=536), Disabled, None, 115200"
In file included from C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.0\cores\esp8266/esp8266_peri.h:24:0,
from C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.0\cores\esp8266/Arduino.h:38,
from sketch\my-svg.ino.ino.cpp:1:
Z:\Скетчи\my-svg\my-svg.ino\my-svg.ino.ino: In function 'void handleRoot()':
C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.0/tools/sdk/include/c_types.h:89:66: error: section attribute cannot be specified for local variables
#define ICACHE_RODATA_ATTR __attribute__((section(".irom.text")))
^
C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.4.0\cores\esp8266/pgmspace.h:13:21: note: in expansion of macro 'ICACHE_RODATA_ATTR'
#define PROGMEM ICACHE_RODATA_ATTR
^
Z:\Скетчи\my-svg\my-svg.ino\my-svg.ino.ino:31:26: note: in expansion of macro 'PROGMEM'
exit status 1
Ошибка компиляции для платы Generic ESP8266 Module.
Что-то лыжи не едут...
Да, нет, скорее второе. Кто Вас так учил символьные константы писать?
Ну... сделайте переменную глобальной, например.
https://www.arduino.cc/reference/en/language/variables/utilities/progmem/
Да, лучше static если она глобально не нужна. Нафига глобальное прострнство имён засорять?
Да, нет, скорее второе. Кто Вас так учил символьные константы писать?
Это на форуме по ESP так нарисовано. Я тоже долго на это пялился, но так и не понял зачем так. Может быть специфика ESP-шного кода...
Нет, это у них длинаая строка перенеслась в движке на форуме. А Вы не поправили. Надо её или одной строкой делать, либо, если уж разбивать, то так, как я написал - на каждой строке в своих кавычках и никаких символов (кроме комменятариев) между ними.
......
При размере данных вплоть до ~2500 байт - esp не крашится.
.....
http://uzebox.org/wiki/ESP8266_AT_Commands
AT+CIPSEND send data: AT+CIPSEND=4,15 and then enter the data MAX 2048 bytes
Нет, это у них длинаая строка перенеслась в движке на форуме. А Вы не поправили. Надо её или одной строкой делать, либо, если уж разбивать, то так, как я написал - на каждой строке в своих кавычках
Мультилайн еще можно забацать, насколько я помню. Но вот еще там какой-то префикс R прилеплен. Не знаю, что это означает.
Подскажите глупому, как отправить русский текст, если отправляю так, то вместо русских букв в браузере отображаются кракозябры.
server.sendContent(
"<html><head></head><body><h1>Привет</h1></body></html>"
);
Есть тег <meta>, в котором можно указать кодировку для браузера - http://htmlbook.ru/html/meta/charset
Поиграйтесь с кодировками: utf-8, windows-1251