Разработка ‘библиотеки’ малого webсервера на esp8266.

pvvx

Активный участник сообщества
Значит, такое предложение (с) "Кин-дза-дза!": Может быть имеет смысл в "свалке" распостранить правило именования переменных в тильдах и на команды передаваемые в POST методе?
Предложение возникло в связи с тем, что иногда нужно передать в дочернюю страницу параметры через POST, и веб-сервер воспринимает это дело как команды и парсит в web_int_vars.c Так-то ничего страшного, но как-то неаккуратно получается.
Вопрос сложный - а надо ли это? :) Возьмите исходники проекта и разместите на github от себя или ещё как. Любые упоминания о источниках можете (и желательно) стереть или указать как свои (т.е. поступайте как захотите). Проект именно для этого и делался. Я его сопровождать не особо собираюсь, а начальную поставленную цель он уже выполнил. Это не отмазка и не посыл. Просто так сложилось и ничего в этом плохого нет... Впереди лето, дети... :)
 
Последнее редактирование:

ToteMeiSter

New member
PVVX, я правильно понял что ты завершил свой проект. Как минимум на данном этапе?
 

pvvx

Активный участник сообщества
PVVX, я правильно понял что ты завершил свой проект. Как минимум на данном этапе?
Типа. Для использования его надо полностью переписывать. Я же не программист и на него не учился. Реализовал решения как смог.
Дописывать можно бесконечно. Как и указывал - там особо нет применения функций со статическими буферами, отъедающими надолго память (кроме TCP2UART). К примеру для реализации скана WiFi надо делать буфер и простой скрипт для поэтапно-кусочного вывода итогов сканирования в XML или прямо в HTML. Но эти буфера будут практически постоянными для других соединений и отнимать память.
Для опроса датчиков и сбора с них данных - аналогично.
Такое и не вставлял, т.к. это уже решение для конкретных задач и как-то к Web-серверу имеет совсем отдаленное отношение... Их проверенная годами при использовании в промышленности реализация у меня есть, но для других MCU и надо только перенести в среду ESP. По тому мене это не нужно :)
Итак там очень много хламу, вставленного для демонстрации, что это всё решаемо и может успешно жить на ESP8266.
Демонстрационная “свалка” была начата когда на ESP8266 предавали один байт и то кое-как, как это и продолжается во многих клонах-портах Lua. Она была создана, для демонстрации, что простым портированием-клонированием чужого ничего хорошего не выйдет. А так-же было очень мало информации - Espressif вредничал. А счас “общество ESP8266” это уже восприняло и программисты начали реализовывать “правильный подход”…
 
Последнее редактирование:

pvvx

Активный участник сообщества
Кто знает как работать с компонентом XML Decode в appinventor?
appinventor.gif
Выводы переключает, но как распарсить XML - :rolleyes:
=======
Нашел. :)
 
Последнее редактирование:

Victor

Administrator
Команда форума

pvvx

Активный участник сообщества
А в сторону OpenHAB не смотрели? Почему именно appinventor выбрали?
Может нам уже пора раздел отдельный на эту тему?
OpenHAB не для совсем детей :) А в appinventor - там всё кубиками, никаких download и install, да поддержка посерьезней :)
-----
Да и обновление в "свалке" - встроен NETBIOS и включается/выключается на страничках Setup...
 
Последнее редактирование:

pvvx

Активный участник сообщества
ESP8266 + Web + AppInventor
appinventor_test.gif :)
led.xml
Код:
<response>
<ledio_inp>~gpio1_inp~</ledio_inp>
</response>
 
Последнее редактирование:

Sanya_kv

New member
Не могу получить доступ к сырым данным (до передачи в стек LwIP). Бьюсь уже довольно продолжительное время периодически переключаясь на этот проект, насколько позволяет основная работа. Может Вы pvvx подскажите? Куда копать.
Заранее благодарен за ответ.
 

pvvx

Активный участник сообщества
Не могу получить доступ к сырым данным (до передачи в стек LwIP).
Все данные передаются в LwIP через временные буфера pbufo и pbufi. В проекте с ними Web и TCP2UART работает через указатели в struct t_TCP_SERV_CONN описанной в "tcp_srv_conn.h" и комент там на русском.
Далее необходимо уточнять, что вам конкретно необходимо...
 

Sanya_kv

New member
Все данные передаются в LwIP через временные буфера pbufo и pbufi. В проекте с ними Web и TCP2UART работает через указатели в struct t_TCP_SERV_CONN описанной в "tcp_srv_conn.h" и комент там на русском.
Не совсем то, с этим как раз все понятно. Вы очень всё доступно расписали, я наконец разобрался как работает Raw API в LwIP.
Я пытаюсь получить доступ к netif->output и к netif->input. (struct netif).
У меня задача перехватить поток на входе функции netif->input. Я не оставляю надежды обойти использование LwIP.
Непосредственно интересует netif->input, победить netif->output почти удалось.
 
Последнее редактирование:

pvvx

Активный участник сообщества
Интересно, что при применении интрасети и обращении по имени из NetBIOS, при передаче файла диска на модуль ESP, windows дает полное имя файла со всеми каталогами:
srv[80] 192.168.1.2:10562 [1] read: 680 of254[/fsupload] 'ESP8266:0123456789' POST f[/fsupload] ...
srv[80] 192.168.1.2:10562 [1] read: 1460 filename:'E:\ESP8266\workspace\Web_Base3\webbin\WEBFiles.bin' ...

В ver 0.1.8 (скоро будет) пришлось отменить проверку имени передаваемого файла для загрузки... Разбирать/парсить ещё имена и файловые структуры всех типов не охота, да и буфера на килобайты полного имени нету и/или жалко :) Все равно файл при загрузке для записи ещё множественное число раз проверяется на заголовок, размер и описание в мультидате и это уже лишнее.

Ещё про интрасеть в IE для доступа по имени с NetBIOS. Оно вырубает отображение графиков на java, в режиме совместимости с устаревшими системами :)
Нашел, что отключается это так:
grf_heap.gif
 
Последнее редактирование:

pvvx

Активный участник сообщества
Опять требуется "помощь зала" :) , кто напишет реализацию в HTMl + простая java вывода сканируемых станций с их выбором для режима Station ?
В версию 0.1.9 добавлен wifi_scan=1 - это вызов сканирования, например, так http://esp8266/web.cgi?wifi_scan=1.
Пока WiFi сканирует станции (это длится несколько секунд), запрос scan.xml выдает:
HTML:
<?xml version="1.0"?>
<response>
<total>0</total>
</response>
Где ноль указывает, что ещё сканируется.
В случае, если за 10 сек нет ответа, надо повторить запрос (для надежности).
Через несколько секунд, по концу опроса модулем станций, получаем такой scan.xml:
HTML:
<?xml version="1.0"?>
<response>
<total>14</total>
<ap id="0">
<ch>1</ch>
<au>4</au>
<bs>xx:xx:xx:xx:xx:xx</bs>
<ss>mxxxxxxxx6</ss>
<rs>-26</rs>
<hd>0</hd>
</ap>
<ap id="1">
<ch>2</ch>
<au>4</au>
<bs>xx:xx:xx:xx:xx:xx</bs>
<ss>InterZetxxxxx</ss>
<rs>-48</rs>
<hd>0</hd>
<rs>-82</rs>
<hd>0</hd>
</ap>
...
<ap id="12">
<ch>11</ch>
<au>2</au>
<bs>78:54:xx:xx:xx:xx</bs>
<ss>DSL-2640U</ss>
<rs>-84</rs>
<hd>0</hd>
</ap>
<ap id="13">
<ch>12</ch>
<au>3</au>
<bs>c4:04:xx:xx:xx:xx</bs>
<ss>HP-Print-bd-LaserJet 200</ss>
<rs>-83</rs>
<hd>0</hd>
</ap>
</response>
Когда будет пример HTML - возможно будут изменения.

В следующих версиях, наверно, будет включен WebSocket :)
Проверить поддержку браузером WebSocket можно пройдя по ссылке:http://caniuse.com/#feat=websockets
 
Последнее редактирование:

Andy Korg

Moderator
Команда форума
кто напишет реализацию в HTMl + простая java
- В цирке идет представление, выступает дрессировщик с крокодилом.
- Дрессировщик бьет палочкой крокодила по голове, тот открывает пасть.
- Дрессировщик достает из штанов член и кладет в пасть крокодилу.
- Крокодил захлапывает пасть.
- Через минуту дрессировщик бьет крокодила палочкой по голове, тот открывает пасть, дрессировщик достает член из пасти и обращается к зрителям :
- "Кто нибудь может повторить этот трюк?"
- В третьем ряду встает одна женщина и говорит:
- "Я бы попробовала, только Вы палочкой больно бьете."
 

pvvx

Активный участник сообщества
У меня задача перехватить поток на входе функции netif->input. Я не оставляю надежды обойти использование LwIP.
А что вместо него? Других претендентов практически нет, а делать из модуля просто передачу пакетов нет особого смысла - есть масса чипов уже с USB портом, для подключения к внешнему MCU и в линуксе к ним драйвера...
 

aloika

Active member
pvvx, в файле web_int_callbacks.c хочется заменить строчку

else if(!os_memcmp((void*)cstr, "time", 4)) tcp_puts("%d", system_get_time());

на

else if(!os_memcmp((void*)cstr, "time", 4)) tcp_puts("%u", system_get_time());

чтобы в выводе значение системного времени было беззнаковое. А то полчаса считает, а потом отрицательное время на веб-страничке получается...
 

pvvx

Активный участник сообщества
А то полчаса считает, а потом отрицательное время на веб-страничке получается...
Отрицательное время - это хорошо :)
Там много где надо это сменить - писалось копированием строк и сменой функций... Махнул во многих местах, не глядя :)
В web_int_callbacks надо что-то придумать, а то слишкоммногокода генерит. Если ещё на переменные натравить WebSocket, то их станет за сотню...
 

Andy Korg

Moderator
Команда форума
В web_int_callbacks надо что-то придумать, а то слишкоммногокода генерит
В сыром проекте использую такую шнягу:
C:
typedef uint8                        //returns the number of processed characters
        (*VOID_PTR_GET_VAR)            //Get function for http-variable
            (WEB_SRV_CONN* web_con,    //Connect to tcp-client
            uint8* cstr);            //Text adres line


typedef uint8                        //returns the number of processed characters
        (*VOID_PTR_SET_VAR)(        //Set function http-varialbe
            WEB_SRV_CONN* web_con,    //Connect to tcp-client
            uint8 *pcmd,            //command line
            uint8 *pvar);             //value variable

typedef enum {
        vtNULL,
        vtString,
        vtErr,                        //Код ошибки из файла err.h
        vtByte,                        //Беззнаковый байт
        vtWord16,                    //Беззнаковое слово
        vtWord32                    //Беззнаковое двойное слово
} varHttpType;

//Описание переменных http
typedef struct{
    uint8 *Name;            //Имя переменной
    varHttpType varType;    //Тип
    char *ArgPrnHttp;        //строка форматирования вывода в http вида "%d"
    void *Value;            //указатель на переменную
    VOID_PTR_GET_VAR execGet;//Функция вызываемая для чтения значения переменной, вызывается первой если определена
    VOID_PTR_SET_VAR execSet;//Функция вызываемая для сохранения значения переменной
    void *Child;            //следующая часть переменной или команды
    uint8 ChildLen;            //Размер дочернего массива, берется как SizeArray(Child)
} pHttpVar;

#define pHttpVarSize    sizeof(*pHttpVar)
#define SizeArray(a)    ((sizeof(a)/sizeof(a[0])))    //Размер массива

#define HTTP_ROOT_LEN    5    //Количество элементов в корневом списке переменых и команд

extern pHttpVar HttpMyRoot[HTTP_ROOT_LEN];    //корневые переменные. Должен быть объявлен в каком-нибудь из файлов

//Для вызова из web_int_vars.h или "вручную"
extern uint8 ICACHE_FLASH_ATTR parseHttpSetVar(pHttpVar *ParentVar, uint8 ParentLen,    //Родительские переменные
        WEB_SRV_CONN *web_conn, uint8 *pcmd, uint8 *pvar);
//Для вызова из web_int_callbacks.c или "вручную"
extern uint8 ICACHE_FLASH_ATTR parseHttpGetVar(pHttpVar *ParentVar, uint8 ParentLen,    //Родительские переменные
        WEB_SRV_CONN *web_conn, uint8 *cstr);

C:
/*
* Обработка вывода значения в http
*/
uint8 ICACHE_FLASH_ATTR parseHttpGetVar(pHttpVar *ParentVar, uint8 ParentLen, WEB_SRV_CONN *web_conn, uint8 *cstr){

    uint8 i, count, Ret = 0;

    if (!strlen(cstr)) return Ret;
    pHttpVar *VarList;

#if (DEBUGSOO==1)
    os_printf("get var %s\n", cstr);
#endif

    VarList = GetArrayVar(ParentVar, &ParentLen);

    for (i = 0; i < ParentLen; i++) {
        if (!os_memcmp((void *) cstr, VarList[i].Name, os_strlen(VarList[i].Name))){
            cstr += os_strlen(VarList[i].Name);
            Ret = os_strlen(VarList[i].Name);
            if ((VarList[i].Value != NULL) && (VarList[i].varType != vtNULL)){
                switch (VarList[i].varType){
                    case vtErr:
                        tcp_puts(VarList[i].ArgPrnHttp, *((err_t*)(VarList[i].Value)));
                      .....
                    default:
                        tcp_puts("bad var type");
                        break;
                }
            }
            if (VarList[i].execGet != NULL){
                uint8 j = VarList[i].execGet(web_conn, cstr);
                cstr += j;
                Ret += j;
            }
            if (VarList[i].Child != NULL){
                Ret += (parseHttpGetVar(VarList[i].Child, VarList[i].ChildLen, web_conn, cstr));
            }
            break;
        }
    }
    return Ret;
}

/*
* Write httpvar to variable
*/
uint8 ICACHE_FLASH_ATTR parseHttpSetVar(pHttpVar *ParentVar, uint8 ParentLen, WEB_SRV_CONN *web_conn, uint8 *pcmd, uint8 *pvar){

    uint8 i, j, Ret = 0;

    if (!strlen(pcmd)) return Ret;

    char *cstr = pcmd;

#if (DEBUGSOO==1)
    os_printf("set var %s\n", cstr);
#endif
    pHttpVar *VarList;

    VarList = GetArrayVar(ParentVar, &ParentLen);

    for (i = 0; i < ParentLen; i++) {
        if (!os_memcmp((void *) cstr, VarList[i].Name, os_strlen(VarList[i].Name))){
            cstr += os_strlen(VarList[i].Name);
            Ret = os_strlen(VarList[i].Name);
            if ((VarList[i].Value != NULL) && (VarList[i].varType != vtNULL)){
                switch (VarList[i].varType){
                    case vtErr:
                        *((err_t*)VarList[i].Value) = (err_t)atoi(pvar);
                        break;
.....
                    default:
                        break;
                }
            }
            if (VarList[i].execSet != NULL){
                uint8 j = VarList[i].execSet(web_conn, cstr, pvar);
                cstr += j;
                Ret += j;
            }
            if (VarList[i].Child != NULL){
                Ret += (parseHttpSetVar(VarList[i].Child, VarList[i].ChildLen, web_conn, cstr, pvar));
            }
            break;
        }
    }
    return Ret;
}

В самом проекте:
C:
//ntp_
pHttpVar HttpNTP[10] = {
    // Name;    varType;     ArgPrnHttp;     Value;             execGet;     execSet;     Child;        ChildLen
    {"second",     vtByte,     "%02x",         &Watch.Second,    NULL,        NULL,         NULL,         0},
    {"minute",     vtByte,     "%02x",         &Watch.Minute,    NULL,        NULL,         NULL,        0},
....
    {"year",     vtByte,     "%02x",         &Watch.Year,    NULL,        NULL,         NULL,        0}
};

//ROOT, объявлен customer_html.c
pHttpVar HttpMyRoot[HTTP_ROOT_LEN] = {
    // Name;    vType;         ArgPrnHttp;     Value;     execGet;     execSet;     Child;            ChildLen
    {"ntp_",     vtNULL,     NULL,             NULL,    NULL,        NULL,        &HttpNTP,         SizeArray(HttpNTP)},
...
    {"ping_",     vtNULL,        NULL,             NULL,    NULL,        NULL,        &HttpPing,         SizeArray(HttpPing)}
};
Недостаток - жрет память, достоинство - все в одном месте и разбито на кучу маленьких функций
 
Последнее редактирование:

pvvx

Активный участник сообщества
Недостаток - жрет память
- Это главное. Всё-же ещё надеюсь сделать так, чтобы не брала ни бита из rodata, heap, bss... Метода есть, но она для "релиза" и делает разводку по символам (ускоряет в несколько раз поиск), но текст СИ не читаем, а препроцессор не доделан...
----
"Свалка" обновлена на SDK 1.0.1 b1 на день раньше релиза (из-за отрицательного времени) :)
В новых доках ("2C-SDK-Espressif IoT SDK Programming Guide_EN_V1.0.1.pdf", в конце) даны указания по калибровке показаний vdd3.3 и т.д.
Попробую с этим что-то сделать.
Для новой версии (0.2.0) добавил ~sys_const_NNN~ и соответственно sys_const_NNN=XXX, где NNN - номер в системных константах (esp_init_data_default.bin), а XXX - число для записи туда. NNN и XXX воспринимается в DEC и HEX.
Описание влияния sys_const 107 и 108 даны в доке "2A-SDK-Espressif IoT SDK User Manual_EN_V1.0.1.pdf":
107: Или ADC (system_adc_read()) или VDD3P3 (system_get_vdd33()). Обе не возможны.
108: deep_sleep_set_option(0)

Типа калибровка для примененной функции в Web readvdd33() теперь запоминается в ~sys_ucnst_0~ ...
 
Последнее редактирование:

Andy Korg

Moderator
Команда форума
Кажись при разборе POST в web_srv.c образовалась ошибка. Например такой url
HTML:
host.html?par1=par+1
(плюсик потом перегоняется в пробел) разбирается в "web_parse_content" только до "par", т.е. пробел в функции cmpcpystr воспринимается как конец строки и дальше в "web_int_vars" уже передается обрезанное значение pvar. Как будет время поправте пожалуйста.
 
Сверху Снизу