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. Тем более, от такого варванского его использования. Уверен, что поможет.
Вот код:
void drawGraph() { char temp1[2500]; snprintf ( temp1, 2500, "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"1000\" height=\"330\">\ <line x1=\"20\" y1=\"0\" x2=\"20\" y2=\"310\" stroke=\"black\"/>\ <line x1=\"20\" y1=\"10\" x2=\"1000\" y2=\"10\" stroke=\"lightgray\"/>\ <line x1=\"20\" y1=\"110\" x2=\"1000\" y2=\"110\" stroke=\"lightgray\"/>\ <line x1=\"20\" y1=\"210\" x2=\"1000\" y2=\"210\" stroke=\"lightgray\"/>\ <line x1=\"20\" y1=\"310\" x2=\"1000\" y2=\"310\" stroke=\"black\"/>\ <text x=\"0\" y=\"15\" fill = \"red\">30</text>\ <text x=\"0\" y=\"115\" fill = \"red\">20</text>\ <text x=\"0\" y=\"215\" fill = \"red\">10</text>\ <text x=\"0\" y=\"315\" fill = \"red\">0</text>\ <text x=\"12\" y=\"325\">00</text>\ <text x=\"52\" y=\"325\">01</text>\ <text x=\"92\" y=\"325\">02</text>\ <text x=\"132\" y=\"325\">03</text>\ <text x=\"172\" y=\"325\">04</text>\ <text x=\"212\" y=\"325\">05</text>\ <text x=\"252\" y=\"325\">06</text>\ <text x=\"292\" y=\"325\">07</text>\ <text x=\"332\" y=\"325\">08</text>\ <text x=\"372\" y=\"325\">09</text>\ <text x=\"412\" y=\"325\">10</text>\ <text x=\"452\" y=\"325\">11</text>\ <text x=\"492\" y=\"325\">12</text>\ <text x=\"532\" y=\"325\">13</text>\ <text x=\"572\" y=\"325\">14</text>\ <text x=\"612\" y=\"325\">15</text>\ <text x=\"652\" y=\"325\">16</text>\ <text x=\"692\" y=\"325\">17</text>\ <text x=\"732\" y=\"325\">18</text>\ <text x=\"772\" y=\"325\">19</text>\ <text x=\"812\" y=\"325\">20</text>\ <text x=\"852\" y=\"325\">21</text>\ <text x=\"892\" y=\"325\">22</text>\ <text x=\"932\" y=\"325\">23</text>\ <circle cx=\"20\" cy=\"270\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"60\" cy=\"280\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"100\" cy=\"265\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"140\" cy=\"265\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"180\" cy=\"260\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"220\" cy=\"250\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"260\" cy=\"250\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"300\" cy=\"250\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"340\" cy=\"250\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ <circle cx=\"380\" cy=\"240\" r=\"3\" stroke=\"black\" stroke-width=\"1\" fill=\"red\" />\ </svg>\n"); server.send ( 200, "image/svg+xml", temp1); }если еще увеличить размер temp1 и добавить строк - esp крашится.
Думаю, что проблема с памятью. Попробуйте для начала избавиться от типа String. Тем более, от такого варванского его использования. Уверен, что поможет.
Делаю как в примере - ни шага в сторону :)
Если на вывод идет текст - как же его пихать, если не как String?
Делаю как в примере - ни шага в сторону :)
Пример - он на то и пример, чтобы показать принцип, используя минимум строк кода. Кроме того, в примере работы с единственным устройством, как правило, ресурсов МК хватает с избытком, так что ради понятности кода эти ресурсы зачастую приносятся в жертву.
В реальном проекте оптимизировать следует по совсем иным принципам.
Если на вывод идет текст - как же его пихать, если не как String?
Вообще-то в Ардуино целесообразнее применять char*. Но если касается вывода - то выводить побайтно можно сообщения вообще неограниченной длины. Т.е. не надо ждать, пока накопится посылка целиком, либо составлять длинную строку из отдельных кусочков: каждый из ее фрагментов выводится побайтно один за другим. Расход ресурсов - 1 байт.
не победил этот snprintf и server.send но хотелось бы. если кто-то сможет подсказать - буду благодарен.
использую
server.sendContent("<html><head><body><h1>Hello from ESP8266!</h1>"); server.sendContent("<svg width=\"1000\" height=\"330\">"); server.sendContent("<line x1=\"20\" y1=\"0\" x2=\"20\" y2=\"310\" stroke=\"black\"/>"); server.sendContent("<line x1=\"20\" y1=\"10\" x2=\"1000\" y2=\"10\" stroke=\"lightgray\"/>"); server.sendContent("<line x1=\"20\" y1=\"110\" x2=\"1000\" y2=\"110\" stroke=\"lightgray\"/>"); server.sendContent("<line x1=\"20\" y1=\"210\" x2=\"1000\" y2=\"210\" stroke=\"lightgray\"/>"); server.sendContent("<line x1=\"20\" y1=\"310\" x2=\"1000\" y2=\"310\" stroke=\"black\"/>"); server.sendContent("</svg>"); server.sendContent("</body></html>");Делаю как в примере - ни шага в сторону :)
Сомневаюсь.
Объект/класс 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"
void setup() {} void loop() { const char index_html[] PROGMEM = R"=====( <!DOCTYPE HTML> <html> <head><title>ESP8266 Arduino Demo Page</title></head> <body>ESP8266 power!<p><img src="logo.png"></body> </html> )====="; }Подробный текст ошибки (вдруг что-то полезное увидите):
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.
Что-то лыжи не едут...
Да, нет, скорее второе. Кто Вас так учил символьные константы писать?
const char index_html[] PROGMEM = "=====(" "<!DOCTYPE HTML>" "<html>" "<head><title>ESP8266 Arduino Demo Page</title></head>" "<body>ESP8266 power!<p><img src=\"logo.png\"></body>" "</html>" ")=====";Ну... сделайте переменную глобальной, например.
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