GyverPortal

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@gorlanovmax, без полного кода я больше ничего не буду Вам писать. От перемены мест дефайнов всё таки что то меняется. сперва по дефолту дефайны с библиотеки..... то есть у Вас проблемы именно с тем, что в момент когда вы определяете портал работают одни дефайны, а вот когда стартуете в секции setup уже другие. Тут надо смотреть всё.
И да, раз тема про портал, то я подумал что у Вас не получается порталом достучаться до файлов, однако как я понимаю у Вас логика программы пишет и читает файл, просто тогда не вижу смысла передавать порталу данные о использованной файловой системы, если Вы запрещаете ему скачивать файлы. (более детально понять принцип работы этого дефайна можно понять, посмотрев файл portal.h). Я не могу гадать и наверное больше никому ничего не буду советовать, пока не увижу достаточного количества кода. Как говорится: Правильно понятая задача - это половина решения.
@gorlanovmax, тут я не понял о чём Вы, но я просто создаю паку в скетче и заливаю данные через утилиту (плагин), она сама всё форматит и сама всё заливает, без дополнительных манипуляций, и всё работает.
@Роман_Л, Раз всё работает, то уже хорошо. Значит всё залилось и значит всё правильно. По поводу wiki, у меня нет к ней доступа, да если бы и был, то не хватило бы времени туда писать, судя по телеге Гайвера, ему просто не хватает 24 часов в сутках на всё, думаю он правильно разделил приоритеты и рано или поздно подойдёт опять к wiki, а пока просто посматривайте файл builder.h, в принципе код очень читабельный и Вам станет понятно как всё делать!
По поводу обновлений и ошибок... не совсем понял о чём Вы, однако проверьте, чтобы в момент загрузки данных (не программы, а именно data upload из инструментов) не был включен монитор порта. При включенном мониторе порта бывают глюки с заливкой данных.
 

gorlanovmax

✩✩✩✩✩✩✩
26 Окт 2022
69
6
@DAK,
Про место расположения дефайнов вы правы, в этом моменте я был не прав.
Поправьте меня, относительно дефайна скачивания файлов.
Я его понимаю, как скачивание файлов из SPIFFS на устройство на котором открыта страница с порталом.
У меня скачивание не используется. Для чего мне тогда излишне нагружать код?
Данные о файловой системе мне передавать надо, т.к. используется OTA.
Относительно предварительного форматирования SPIFFS.
Отдельно без форматирования заливку файлов через плагин не проверял.
У меня файлы создаются в процессе работы скетча.

Однако замечу, что если например надо просто реализовать возможность обновления устройства по OTA, нет необходимости заранее заливать в SPIFFS данные.
Но при этом при подключении хранилища выходит ошибка.
И включенная опция "форматировать если неисправно" не работает
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@gorlanovmax, я никогда не думал об этой проблеме с такой стороны (в плане нагрузки на МК), спорить не собираюсь, просто поделюсь своим опытом в работе портала. И так:
1. Файловая система всё равно подгружается, поиграйте этим девайном и посмотрите на сколько байт ваша программа будет больше или меньше кушать озу и пзу. Мне кажется, что больших отличий Вы и не заметите, однако я бы проверил эти параметры.
2. Загрузка файлов нагружает МК только в процессе запроса к файлу, нет запроса, нет загрузки МК
3. Если перейти на использование файлов стилей и скриптов, вместо генерации их функциями портала, то Вы приятно удивитесь. Файлы загрузятся ровно 1 раз и всё, они будут в кэше браузера, а код, который генерируется МК станет в 2-3 раза меньше, вот этим Вы действительно снизите нагрузку на МК и значительно ускорите работу алгоритма.
По поводу
И включенная опция "форматировать если неисправно" не работает
хотел уточнить про какую опцию идёт речь и не могу понять как это касается работы портала? Без инициализации портала это работает, с инициализацией - не работает, так? Или это просто не касается портала?
 

gorlanovmax

✩✩✩✩✩✩✩
26 Окт 2022
69
6
Если перейти на использование файлов стилей и скриптов
Спасибо, вы имеете ввиду, положить файлы скриптов и стилей в хранилище и использовать функции типа GP.BUILD_BEGIN_FILE?
Здесь проблема в следующем: хранилище отформатировано.
Подключается, но пишет ошибку
[E][vfs_api.cpp:104] open(): /littlefs/gp_data does not exist, no permits for creation
Хотя файлы по указанному пути положены
Другие файлы, которые я сам создаю из скетча видит, читает, записывает.

хотел уточнить про какую опцию идёт речь
При подключении хранилища, можно указать true
В стандартном примере библиотеки LittleFS это форматирует хранилище если его не удалось монтировать.
Но при использовании в скетче с подключенной библиотекой портала, форматирование не происходит.
Предположение, только что как-то влияет ссылка на хранилище порталу
GyverPortal portal(&LittleFS);
 

Kbaccok

✩✩✩✩✩✩✩
28 Окт 2022
4
0
@ASM,
""я вот это не понимаю) по нажатию какой кнопки) этой?) --GP.SUBMIT(текст); // кнопка отправки формы""

Нет. Как я понял GP.SUBMIT(текст); Обновляет всю страницу. (ну или я как-то смог написать, что при нажатии обновляется вся страница и данные пишутся в переменную) Так работает, но для меня всю страницу обновлять не надо.
Необходимо по нажатию GP.BUTTON_MINI(имя, текст, id); записать введенные значения из GP.NUMBER_F(имя, подсказка, число, знаков); в переменную.
Не совсем понятно что есть (имя, текст, id) в GP.BUTTON_MINI, или же в GP.NUMBER_F(имя, подсказка, число, знаков). Я с этим запутался в край
Я явно что-то делаю не так. Не могу понять что именно.

Мне кажется если раз сможете мне описать, как для чайника, я думаю больше вопросов не возникнет. Дальше сам поковыряю на базе примеров.


C++:
//Вот так не работает
void build()
    GP.NUMBER_F("Temperatura", "number4", pid.setpoint);
     GP.BUTTON("btn", "Button");
void action() {
  if (portal.click()) {
    // проверяем компоненты и обновляем переменные
    if (portal.click("btn")) {
    pid.setpoint = portal.getFloat("Temperatura");
    }
    }
}

// А так отрабатывает
void build() {
    GP.FORM_BEGIN("/update") 
    GP.NUMBER_F("Temperatura", "number4", pid.setpoint); GP.BREAK(); 
    GP.SUBMIT("Submit");
    GP.FORM_END();
    void action() {
        if (portal.form()) {
        if (portal.form("/update")) {
        pid.setpoint = portal.getFloat("Temperatura");
        }
        }
    }
 

Kbaccok

✩✩✩✩✩✩✩
28 Окт 2022
4
0
@DAK, Веб морда заработала, я разобрался где накосячил @DAK,

Веб морда заработала. Я разобрался где накосячил.
Столкнулся с проблемой, что при нажатии на кнопку GP.BUTTON введенные значения в GP.NUMBER_F не изменяют переменной pid.setpoint.
Как корректно написать? Выделил

C++:
void build() {
    GP.BUILD_BEGIN();
    GP.THEME(GP_DARK);
    GP.NUMBER_F("Temperatura", "number4", pid.setpoint); GP.BREAK();
    GP.BUTTON("btn", "Button","Temperatura");
    GP.BUILD_END()
void setup() {
  Serial.begin(115200);
  Serial.setTimeout(100);
  pid.setpoint = 50; 
 
  WiFi.mode(WIFI_STA);
  WiFi.begin(AP_SSID, AP_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(WiFi.localIP());

  portal.attachBuild(build);
  portal.attach(action);
  portal.start();
}

    void action() {
      if (portal.click()) {
    if (portal.click("btn")) {
        pid.setpoint = portal.getFloat("Temperatura");
    }}}
    
void loop() {
  portal.tick();
 

ASM

★★★★★✩✩
26 Окт 2018
1,599
311
Не совсем понятно что есть (имя, текст, id) в GP.BUTTON_MINI
имя кнопки (для парсинга, например), текст на кнопке, id (название переменной для обращения, например для обновления)
GP.NUMBER_F(имя, подсказка, число, знаков);
имя этого поля (для парсинга, например), подсказка текстовая в самом поле (placeholder), значение этого поля, число знаков после запятой

C++:
if (portal.click("btn")) { pid.setpoint = portal.getFloat("Temperatura");
так по нажатию кнопки не происходит отправка значений, Submit отправляет все данные из формы.

есть ли другой вариант, не знаю, мне не нужен был, скорее всего нужно почитать про Update, надо почитать документацию)
 
  • Лойс +1
Реакции: Kbaccok

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@Kbaccok, у Вас всё понятно, нажатие меняет, просто после нажатия не обновляется страница.
вот ваше решение:
C++:
void build() {
    GP.BUILD_BEGIN();
    GP.setReloadTimeout(120); //можно и не писать, по умолчанию будет ребутить через 150 (просто для понимания как регулировать задержку)
    GP.THEME(GP_DARK);
    GP.NUMBER_F("Temperatura", "number4", pid.setpoint); GP.BREAK();
    GP.BUTTON("btn", "Button","Temperatura",GP_GREEN,"",false,true);
    GP.BUILD_END();
}
Этот код будет обновлять всё страницу через 120 мс после нажатия на кнопку btn.
Думаю этого вам хватит, хотя могли использовать форму и кнопку submit. Примеров много.
 
  • Лойс +1
Реакции: Kbaccok

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@gorlanovmax, не знаю, у всех работает, может проблема где то у Вас. Для понимания надо структуру каталога с кодом и код. Нет этого, нет разговора. Ячестно пытался Вам помочь, но я устал гадать, далее не вижу смысл тратить время не понятно зачем.
 

gorlanovmax

✩✩✩✩✩✩✩
26 Окт 2022
69
6
@DAK,
Огромное спасибо за участие.
Разобрался с проблемой
[E][vfs_api.cpp:104] open(): /littlefs/gp_data does not exist, no permits for creation
Влиял указанный дефайн GP_NO_DOWNLOAD
При его отсутствии в скетче все ок.

У меня остается только вопрос, относительно редиректа при использовании mDNS.
Об этом я писал ранее.
При использовании mDNS при подключении к ESP32 настроенному в качестве точки доступа, на телефоне страница открывается внутри приложения wi-fi, переадресация по имени хоста, указанного в portal.start(esp32).
На десктопе в браузере при подключении к ESP32 открывается страница http://www.msftconnecttest.com/redirect и редиректа на имя хоста указанного в portal.start(esp32) также не происходит.
В пример приводил авторизацию в публичных wi-fi сетях
Например видео

Но это уже вопрос к разработчику библиотеки
 

gorlanovmax

✩✩✩✩✩✩✩
26 Окт 2022
69
6
Еще вопрос к разработчику:
Не планировали реализовать получение времени даты с клиента?
Чтобы использовать при построении страницы для отображения например окна лога
 

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@gorlanovmax, чтобы задать вопрос разработчику надо зарегистрироваться на гитхабе и создать issue, так будет быстрее, только есть пару НО
1. вот код из portal.h
C++:
#ifdef ESP8266
#include <ESP8266WebServer.h>
extern ESP8266WebServer *_gp_s;
#else
#include <WebServer.h>
extern WebServer *_gp_s;
#endif
Касаемо dns mdns, если Вы внимательно посмотрите код, то если я правильно всё понимаю, используется сторонняя библиотека, а не библиотека портала для организации работы логики данных алгоритмов. Надо гуглить и смотреть как сделать всё правильно. Портал просто подключает библиотеки и передаёт в них переменные. Возможно надо как то иначе делать, лично я не готов ответить..... Надо сперва нагуглить как правильно юзать эти штуки, потом попробовать отдельно с ними поиграться.
2. Я допустим понимаю, что при входе на страницу, вы откроете интерфейс, где код явы возьмёт время с компьютера и передаст его и прочее и прочее, но лично я думаю, что это не дело веб сервера... то есть за мою память ни apache ни nginx не брали время с машины и не ставили на его основе время сервера, на котором крутятся. Это можно сделать, но зачем?
Я кину ссылку на Ваш пост выше, но ничего не обещаю, а то Алекс меня забанит навсегда.
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
а то Алекс меня забанит навсегда
Это слухи, я так не делаю с полезными людьми))

реализовать получение времени даты с клиента?
Возможно, я как раз сейчас этим занимаюсь но в рамках другой библиотеки. Здесь скорее всего тоже получится добавить

На десктопе в браузере при подключении к ESP32 открывается страница http://www.msftconnecttest.com/redirect
Всё правильно, так и должно работать. Насколько я понял. Чтобы зайти по указанному имени - нужно зайти по указанному имени, так и работает мднс. А майкрософт редирект закидывает на айпишник. Для мднс используется стандартная библиотека, все вопросы к ней
 
Изменено:

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
Если правильно понял, клиент не сообщает своё время.
1667386290139.png

Сделаю через JS, идея хорошая)
 
Изменено:

DAK

★★★✩✩✩✩
8 Окт 2020
517
137
@AlexGyver, ну да, надо сделать страничку, которая получает дату с компа, потом её передать в портал, тут скорей всего наверное придётся сделать кнопку "синхронизировать", а вот потом на есп принять и поставить, по другому просто наверное не получится. просто так ничего с компа или с телефона не уйдёт, это как минимум небезопаснос, поэтому веб технологи и работают по системе нипель
 

gorlanovmax

✩✩✩✩✩✩✩
26 Окт 2022
69
6
@AlexGyver,

Да, вот здесь обсуждали через JS
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
Я уже сделал. Портал сам периодически выводит на страницу скрипт, отправляющий время на сервер. Актуальное время считается с опорой на миллис - достаточно один раз открыть страницу после включения МК и точное время будет доступно всегда (с точностью миллис), через заданный период само автоматически повторно синхронизируется. Юзеру вообще ничего делать не нужно, всё прозрачно и работает само. Просто забираем готовое время и дату в формате библиотеки GPdate / GPtime, часовой пояс также определяется сам. Пример использования:
C++:
  GP.DATE("d", portal.getSystemDate());
  GP.TIME("t", portal.getSystemTime());
1667391169154.png
 
  • Лойс +1
Реакции: gorlanovmax

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
закинул обновки в репозиторий (пока не релиз), ковыряйтесь)
 
  • Лойс +1
Реакции: gorlanovmax

gorlanovmax

✩✩✩✩✩✩✩
26 Окт 2022
69
6
@AlexGyver,

Подскажите пожалуйста относительно Лога,
Я правильно понимаю, что у блока нельзя задать кастомную ширину?
И перенос строк текста, если он не влезает в одну строку также не работает?
 
Изменено:

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
В обновлении 3.3 ширину можно будет задать. Перенос текста у меня работает, возможно он появился сам собой в версии 3.3, раньше не помню как было
 

gorlanovmax

✩✩✩✩✩✩✩
26 Окт 2022
69
6
Тестирую автоматическую загрузку файлов в SPIFFS
Пробую через кнопку загрузки каталога.
В стандартном примере fileUploadAuto добавляю кнопку загрузки каталога
C++:
//  GP.FILE_UPLOAD("file_upl");    // кнопка загрузки
  GP.FOLDER_UPLOAD("fold_upl");    // кнопка загрузки
При попытке загрузки каталога, идет запрос от браузера, подтвердить загрузку.
1667408481796.png
После подтверждения, страница просто обновляется.
Загрузки не происходит.

При этом загрузка файлов идет нормально.
Проверил на разных браузерах. Результат одинаковый.

И в примере не реализован вывод каталогов, только перечень файлов из корня
 

Barmer

✩✩✩✩✩✩✩
3 Ноя 2022
4
0
Не могу обновить время на форме.
В строке 46 указываю имена каких компонентов данные которых необходимо обновлять. Это индикатор LED и компонент выбора времени.
В строках со 123 по 135 проверяю обновление формы и отправляю значение состояния индикатора и текущее время. Отправляю текущее время также в серийный порт. Индикатор на форме отрабатывает ожидаемо. Время в порту меняется как и задумано.
Перепробовал два варианта обновления ручное и автоматическое как указано в примере: https://github.com/GyverLibs/GyverPortal/blob/main/examples/demos/actionUpdate/actionUpdate.ino
В результате время на форме не обновляется.

Что не так делаю?
Спасибо!

PS. Обновляя страницу в браузере, время отображается корректно.

ActionUpdate:
#define AP_SSID "********"
#define AP_PASS "********"

#include <GyverPortal.h>
GyverPortal portal;

int SpeedTime;
int DelayTime;
GPtime UpTime;
GPtime DownTime;
GPtime CurrentTime;
bool state;
bool LedRedState;
// NTP синхронизация
#include <time.h>

time_t tnow;
struct tm ptm;
int TimeCorrect = 0;
const char *ntpServer = "time.google.com";

#include <ESP32Time.h>
ESP32Time rtc(3600 * 5); // offset in seconds GMT+5

#include <EEPROM.h>
#define INIT_ADDR 100 // номер резервной ячейки
#define INIT_KEY 50   // ключ первого запуска. 0-254, на выбор
#define ADR_UpTimeHour 0
#define ADR_UpTimeMin 1
#define ADR_UpTimeSec 2
#define ADR_DownTimeHour 3
#define ADR_DownTimeMin 4
#define ADR_DownTimeSec 5
#define ADR_SpeedTime 6
#define ADR_DelayTime 10

// конструктор страницы
void build()
{
  BUILD_BEGIN();

  GP.THEME(GP_DARK);
  GP.TITLE("Ручное управление");

 
  GP.UPDATE("LedRed, NCurrentTime");
  GP.BLOCK_BEGIN();
 
  GP.LABEL("Вкл/выкл:");
  GP.SWITCH("sw1", state);
  GP.BREAK();
  GP.LABEL("Текущее время:");
  GP.TIME("NCurrentTime", CurrentTime);
  GP.BREAK();
  GP.LED_RED("LedRed", LedRedState);
 
  GP.BLOCK_END();

  GP.BLOCK_BEGIN();
  GP.LABEL("Время восхода");
  GP.TIME("UpTime", UpTime);
  GP.HR();
  GP.LABEL("Время захода");
  GP.TIME("DownTime", DownTime);
  GP.HR();
  GP.LABEL("Скорость включения");
  GP.SLIDER("sld", SpeedTime, 0, 10);
  GP.HR();
  GP.LABEL("Задержка выключения");
  GP.SLIDER("sld1", DelayTime, 0, 30); //
  GP.HR();
  GP.BREAK();
  GP.BUTTON_LINK("/ota_update", "ota_update");
  GP.BLOCK_END();
  BUILD_END();
}

void action()
{
  // был клик по компоненту
  if (portal.click())
  {
    if (portal.click("sw1"))
    {
      state = portal.getCheck("sw1");
      LedRedState = state;
    }

    if (portal.click("sld"))
    {
      SpeedTime = portal.getInt("sld");
    }

    if (portal.click("sld1"))
    {
      DelayTime = portal.getInt("sld1");
    }

    if (portal.click("DownTime"))
    {
      DownTime = portal.getTime("DownTime");
    }

    if (portal.click("UpTime"))
    {
      UpTime = portal.getTime("UpTime");
    }

    if (portal.click("Save1"))
    {
      EEPROM.write(ADR_UpTimeHour, UpTime.hour);
      EEPROM.write(ADR_UpTimeMin, UpTime.minute);
      EEPROM.write(ADR_UpTimeSec, UpTime.second);
      EEPROM.write(ADR_DownTimeHour, DownTime.hour);
      EEPROM.write(ADR_DownTimeMin, DownTime.minute);
      EEPROM.write(ADR_DownTimeSec, DownTime.second);
      EEPROM.put(ADR_SpeedTime, SpeedTime);
      EEPROM.put(ADR_DelayTime, DelayTime);
      EEPROM.commit();
    }
  }
  if (portal.update())
  {
    // 1. ищем, какой компонент запрашивает обновление
    // и вручную отправляем рандомное значение
    if (portal.update("LedRed"))
      portal.answer(LedRedState);
    if (portal.update("NCurrentTime"))
    {
      portal.answer(CurrentTime);
        Serial.print("NCurrentTime: ");
      Serial.println(CurrentTime.encode());
    }
    // portal.updateTime("NCurrentTime", CurrentTime);
  }
}

void setup()
{
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(AP_SSID, AP_PASS);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(WiFi.localIP());
  configTime(0, 3600, ntpServer);
  if (!getLocalTime(&ptm))
  {
    Serial.println("Could not obtain time info");
  }
  else
  {
    CurrentTime.hour = ptm.tm_hour;
    CurrentTime.minute = ptm.tm_min;
    CurrentTime.second = ptm.tm_sec;
    rtc.setTimeStruct(ptm);
  }
  EEPROM.begin(200);
  if (EEPROM.read(INIT_ADDR) != INIT_KEY)
  { // первый запуск
    EEPROM.write(INIT_ADDR, INIT_KEY); // записали ключ
    EEPROM.commit();
    UpTime.set(7, 0, 0);
    DownTime.set(23, 0, 0);
    SpeedTime = 5;
    DelayTime = 15;

    EEPROM.write(ADR_UpTimeHour, UpTime.hour);
    EEPROM.write(ADR_UpTimeMin, UpTime.minute);
    EEPROM.write(ADR_UpTimeSec, UpTime.second);
    EEPROM.write(ADR_DownTimeHour, DownTime.hour);
    EEPROM.write(ADR_DownTimeMin, DownTime.minute);
    EEPROM.write(ADR_DownTimeSec, DownTime.second);
    EEPROM.put(ADR_SpeedTime, SpeedTime);
    EEPROM.put(ADR_DelayTime, DelayTime);
    EEPROM.commit();
  }
  else
  {
    UpTime.hour = EEPROM.read(ADR_UpTimeHour);
    UpTime.minute = EEPROM.read(ADR_UpTimeMin);
    UpTime.second = EEPROM.read(ADR_UpTimeSec);
    DownTime.hour = EEPROM.read(ADR_DownTimeHour);
    DownTime.minute = EEPROM.read(ADR_DownTimeMin);
    DownTime.second = EEPROM.read(ADR_DownTimeSec);
    EEPROM.get(ADR_SpeedTime, SpeedTime);
    EEPROM.get(ADR_DelayTime, DelayTime);
  }
  // подключаем конструктор и запускаем
  portal.attachBuild(build);
  portal.start();
  portal.enableOTA(); // без пароля
  portal.attach(action);
}

void loop()
{
  portal.tick();
  CurrentTime.hour = rtc.getHour(true);
  CurrentTime.minute = rtc.getMinute();
  CurrentTime.second = rtc.getSecond();
}
@Barmer,
Хммм.
Поменял местами индикатор LED и компонент выбора времени время стало обновляться а индикатор перестал работать.

GP.UPDATE("NCurrentTime, LedRed");


Ну в общем победил. Убрал пробелы из списка имён и всё заработало.
Кстати можно отдельно описывать все имена. Так тоже работает.


GP.UPDATE("LedRed");
GP.UPDATE("NCurrentTime");
 

AlexGyver

★★★★★★✩
Команда форума
30 Июл 2018
359
573
@gorlanovmax, у есп32 видимо криво реализована littlefs, на 8266 работает
1667551052670.png

И в примере не реализован вывод каталогов, только перечень файлов из корня
Будет в обновлении 3.3
 
Изменено: