GyverPortal

Charlot

✩✩✩✩✩✩✩
11 Фев 2025
3
1
Всем привет. Столкнулся с проблемой того, что GyverPortal не хочет строить графики в режиме точки доступа Wifi.AP. Я полагаю что библиотеке нужно получать время из интернета, а в режиме точки доступа интернета нет. Подскажите, в правильном направлении ли я мыслю и как задать время не опираясь на NTP, а прямо в коде
 

SoftFelix

★✩✩✩✩✩✩
16 Фев 2020
48
12
@Charlot,

1. Не все графики работают off-line. Т.е. без и-нета.
2. Из папки библиотеки нужно скопировать папку data целиком в папку со скетчем! Там off-line скрипты для работы графиков.
3. В проекте должна быть инициализированная файловая система. LittleFS, к примеру. Вот тут не совсем уверен, нужно ли это.
4. Специальным плагином типа ESP32 Sketch Data Upload к Arduino IDE нужно загрузить в файловую систему контроллера папку data. Это как процесс заливки прошивки в мк. Плагин всегда ищет папку data для загрузки в папке со скетчем!
5. В параметрах графика в самом конце опцию local обязательно выставить в 1.

C++:
GP.PLOT_STOCK_DARK<2, 15>("plot_temp", temp_name_graph, graphHourTime, tempHourDay, 10, 400, 1);
NTP тут вообще не причём.

Далее компилить примеры библиотеки для графиков и пытаться получить результат.
 
  • Лойс +1
Реакции: Charlot

Charlot

✩✩✩✩✩✩✩
11 Фев 2025
3
1
Сделал как написано, почему-то всё равно график не отображается. Специально проверил чтобы у функции графика была переменная local и передал значение 1. Может в коде где-то ошибся?

C++:
#include <LittleFS.h>
#include <GyverPortal.h>

#define humidity_sensor_pin 0

GyverPortal ui(&LittleFS); // для проверки файлов


int humidity = 0;
int max_humidity = 250;



GPdate nowDate;

GPtime nowTime;

int valNum;



// поддержка wifi связи
void wifiSupport() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.softAP("MyESP8266", "12345678");
    WiFi.softAPConfig(IPAddress(192,168,4,1), IPAddress(192,168,4,1), IPAddress(255,255,255,0));
    Serial.println(WiFi.localIP());
  }
}//wifiSupport()


// конструктор страницы
void build() {
 
  GP.BUILD_BEGIN();
  GP.THEME(GP_DARK);
  GP.PAGE_TITLE("StartUp");
  GP.ONLINE_CHECK();


  GP.BUILD_BEGIN();
  GP.THEME(GP_DARK);
  GP.AJAX_PLOT("plot1", 1, 200, 30000,400,1);

  GP.BUILD_END();


  GP.UPDATE("nowDate,nowTime");
  GP.TITLE("График влажности в %", "t1");
  GP.HR();

  GP.BUTTON("btn", "Калибровка");
  GP.BREAK();
  GP.BREAK();
  GP.BUILD_END();
}


void action() {
  // было обновление
 
 if (ui.update("plot1")) ui.answer(humidity); // установка значения


  //ui.update();
  // был клик по компоненту внутри веб странички
  if (ui.click()) {
    if (ui.click("btn")) {
      max_humidity = humidity;
      Serial.println("Button click");
      Serial.println(max_humidity);
    }
  }//ui.click()
}//action()


void setup() {
  Serial.begin(115200);
  wifiSupport();
  pinMode(humidity_sensor_pin, INPUT);
  // подключаем конструктор и запускаем
  ui.attachBuild(build);
  ui.attach(action);
  ui.start();

  if (!LittleFS.begin()) Serial.println("FS Error");
  ui.downloadAuto(true);
    wifiSupport();
}//setup()


void loop() {

  ui.tick();
  static uint32_t tmr1;
  if (millis() - tmr1 >= 5000) {
    tmr1 = millis();
    humidity = analogRead(humidity_sensor_pin);
    humidity = map(humidity,max_humidity,1023,100,0);
  }

}
 

SoftFelix

★✩✩✩✩✩✩
16 Фев 2020
48
12
@Charlot, где переменные отметок времени и даты для графика? Примеры из библиотеки работают? Папку data загрузил в фс после прошивки?
 
  • Лойс +1
Реакции: Charlot

Charlot

✩✩✩✩✩✩✩
11 Фев 2025
3
1
@SoftFelix,Спасибо! Изначально не тот файл распаковал в папку tools для файловой системы и из-за этого data не загружалась, но кнопка загрузки в "инструменты" была. Всё работает
 
  • Лойс +1
Реакции: SoftFelix

RomaT

★✩✩✩✩✩✩
5 Ноя 2019
117
39
А кто -нибудь под freertos случаем портал не переписывал? пока я страдать не начал...:LOL:
 

kmarakov

✩✩✩✩✩✩✩
29 Июн 2024
6
0
Новый день, новая проблема. Нужно перенести мой портал с wifi на ethernet. Изначально код работал на esp8266. Купил модуль wt32-eth01, прошил, все работает ровно так же. Как теперь заставить работать портал по кабелю? Пробовал тестовые скетчи от библиотеки WebServer_WT32_ETH01, все с ними нормально, но как вместо hello world заставить его показать мне портал?
 

RomaT

★✩✩✩✩✩✩
5 Ноя 2019
117
39

@kmarakov,
Советую сразу забить на Ардуино и на портал и переезжать на родной фреймворк.
Задача какая?
 

kmarakov

✩✩✩✩✩✩✩
29 Июн 2024
6
0
@RomaT,
У меня работает проект на weemos mini. К нему по i2c подключено несколько расширителей портов pcf8574, на них висят реле и обратная связь. Соответственно я этими реле щелкаю через веб морду, и вижу какие включены, какие нет. Быстро, компактно, и дёшево, что самое главное. Появилась необходимость сделать тоже самое, но без вай фая, в конечной инфраструктуре его нет и не будет.
Не знаю даже какой кусок кода привести в пример... Любой пример из библиотеки GyverPortal подойдет.
Пример из Гайвер Портал:
// почти все компоненты

#define AP_SSID ""
#define AP_PASS ""

#include <GyverPortal.h>
GyverPortal ui;

void build() {
  GP.BUILD_BEGIN();
  GP.THEME(GP_DARK);
  //GP.THEME(GP_LIGHT);

  GP.TITLE("GyverPortal");
  GP.HR();

  GP.NAV_TABS_LINKS("/,/home,/sett,/kek", "Home,Settings,Kek");
 
  M_SPOILER(
    "Spoiler",
    GP.LABEL("Hello!");
  );

  M_BLOCK(
    GP.LABEL("Checks & LED");
    GP.BREAK();
    GP.LABEL_BLOCK("label block");
    GP.LED("");
    GP.CHECK("");
    GP.SWITCH("");
  );

  M_BLOCK_TAB(
    "Block Tab",
    GP.LABEL("Inputs");
    M_BOX(GP.LABEL("Number");   GP.NUMBER("", "", 123);     );
    M_BOX(GP.LABEL("Float");    GP.NUMBER_F("", "", 3.14);  );
    M_BOX(GP.LABEL("Text");     GP.TEXT("", "", "Hello");   );
    M_BOX(GP.LABEL("Password"); GP.PASS("", "", "Pass");    );
    GP.AREA("", 3, "Text area");
  );

  M_BLOCK_THIN(
    M_BOX(GP.LABEL("Date");   GP.DATE("");  );
    M_BOX(GP.LABEL("Time");   GP.TIME("");  );
    M_BOX(GP.LABEL("Color");  GP.COLOR(""); );
  );

  M_BLOCK_THIN_TAB(
    "Thin Tab",
    GP.LABEL("Upload File/Folder");
    M_BOX(
      GP_CENTER,
      GP.FILE_UPLOAD("");
      GP.FOLDER_UPLOAD("");
    );
  );

  M_BOX(GP.LABEL("Select");   GP.SELECT("", "Some,Drop,List");  );
  M_BOX(GP.LABEL("Slider");   GP.SLIDER("");  );
  M_BOX(GP.LABEL("Spinner");  GP.SPINNER(""); );

  GP.BUTTON("", "Button");
  GP.BUTTON_MINI("", "Btn Mini");

  GP.BUILD_END();
}

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());

  // подключаем конструктор и запускаем
  ui.attachBuild(build);
  ui.attach(action);
  ui.start();
}

void action() {
}

void loop() {
  ui.tick();
}

Пример веб сервера работающего по Ethernet из библиотеки WebServer_WT32_ETH01.h:
/****************************************************************************************************************************
  WebServer.ino - Simple Arduino web server sample for Ethernet shield
 
  For Ethernet shields using WT32_ETH01 (ESP32 + LAN8720)

  WebServer_WT32_ETH01 is a library for the Ethernet LAN8720 in WT32_ETH01 to run WebServer

  Based on and modified from ESP8266 https://github.com/esp8266/Arduino/releases
  Built by Khoi Hoang https://github.com/khoih-prog/WebServer_WT32_ETH01
  Licensed under MIT license
 *****************************************************************************************************************************/


#define DEBUG_ETHERNET_WEBSERVER_PORT       Serial

// Debug Level from 0 to 4
#define [I]ETHERNET_WEBSERVER_LOGLEVEL[/I]       3

#include <WebServer_WT32_ETH01.h>

WiFiServer server(80);

// Select the IP address according to your local network
IPAddress myIP(192, 168, 0, 232);
IPAddress myGW(192, 168, 0, 1);
IPAddress mySN(255, 255, 255, 0);

// Google DNS Server IP
IPAddress myDNS(8, 8, 8, 8);

int reqCount = 0;                // number of requests received

void setup()
{
  Serial.begin(115200);
  while (!Serial);

  // Using this if Serial debugging is not necessary or not using Serial port
  //while (!Serial && (millis() < 3000));

  Serial.print("\nStarting WebServer on " + String(ARDUINO_BOARD));
  Serial.println(" with " + String(SHIELD_TYPE));
  Serial.println(WEBSERVER_WT32_ETH01_VERSION);

  // To be called before ETH.begin()
  WT32_ETH01_onEvent();

  //bool begin(uint8_t phy_addr=ETH_PHY_ADDR, int power=ETH_PHY_POWER, int mdc=ETH_PHY_MDC, int mdio=ETH_PHY_MDIO,
  //           eth_phy_type_t type=ETH_PHY_TYPE, eth_clock_mode_t clk_mode=ETH_CLK_MODE);
  //ETH.begin(ETH_PHY_ADDR, ETH_PHY_POWER, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_TYPE, ETH_CLK_MODE);
  ETH.begin(ETH_PHY_ADDR, ETH_PHY_POWER);

  // Static IP, leave without this line to get IP via DHCP
  //bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = 0, IPAddress dns2 = 0);
  //ETH.config(myIP, myGW, mySN, myDNS);

  WT32_ETH01_waitForConnect();

  // start the web server on port 80
  server.begin();
}

void loop()
{
  // listen for incoming clients
  WiFiClient client = server.available();

  if (client)
  {
    Serial.println(F("New client"));
    // an http request ends with a blank line
    bool currentLineIsBlank = true;

    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank)
        {
          Serial.println(F("Sending response"));

          // send a standard http response header
          // use \r\n instead of many println statements to speedup data send
          client.print(
            "HTTP/1.1 200 OK\r\n"
            "Content-Type: text/html\r\n"
            "Connection: close\r\n"  // the connection will be closed after completion of the response
            "Refresh: 20\r\n"        // refresh the page automatically every 20 sec
            "\r\n");
          client.print("<!DOCTYPE HTML>\r\n");
          client.print("<html>\r\n");
          client.print(String("<h2>Hello World from ") + BOARD_NAME + "!</h2>\r\n");
          client.print("Requests received: ");
          client.print(++reqCount);
          client.print("<br>\r\n");
          client.print("<br>\r\n");
          client.print("</html>\r\n");
          break;
        }

        if (c == '\n')
        {
          // you're starting a new line
          currentLineIsBlank = true;
        }
        else if (c != '\r')
        {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(10);

    // close the connection:
    client.stop();
    Serial.println(F("Client disconnected"));
  }
}
 

RomaT

★✩✩✩✩✩✩
5 Ноя 2019
117
39
@kmarakov,
C++:
#define DEBUG_ETHERNET_WEBSERVER_PORT       Serial

// Debug Level from 0 to 4
#define [I]ETHERNET_WEBSERVER_LOGLEVEL[/I]       3

#include <WebServer_WT32_ETH01.h>
#include <GyverPortal.h>

GyverPortal ui;

//WiFiServer server(80);

// Select the IP address according to your local network
IPAddress myIP(192, 168, 0, 232);
IPAddress myGW(192, 168, 0, 1);
IPAddress mySN(255, 255, 255, 0);

// Google DNS Server IP
IPAddress myDNS(8, 8, 8, 8);

int reqCount = 0;                // number of requests received

void build() {
  GP.BUILD_BEGIN();
  GP.THEME(GP_DARK);
  //GP.THEME(GP_LIGHT);

  GP.TITLE("GyverPortal");
  GP.HR();

  GP.NAV_TABS_LINKS("/,/home,/sett,/kek", "Home,Settings,Kek");
 
  M_SPOILER(
    "Spoiler",
    GP.LABEL("Hello!");
  );

  M_BLOCK(
    GP.LABEL("Checks & LED");
    GP.BREAK();
    GP.LABEL_BLOCK("label block");
    GP.LED("");
    GP.CHECK("");
    GP.SWITCH("");
  );

  M_BLOCK_TAB(
    "Block Tab",
    GP.LABEL("Inputs");
    M_BOX(GP.LABEL("Number");   GP.NUMBER("", "", 123);     );
    M_BOX(GP.LABEL("Float");    GP.NUMBER_F("", "", 3.14);  );
    M_BOX(GP.LABEL("Text");     GP.TEXT("", "", "Hello");   );
    M_BOX(GP.LABEL("Password"); GP.PASS("", "", "Pass");    );
    GP.AREA("", 3, "Text area");
  );

  M_BLOCK_THIN(
    M_BOX(GP.LABEL("Date");   GP.DATE("");  );
    M_BOX(GP.LABEL("Time");   GP.TIME("");  );
    M_BOX(GP.LABEL("Color");  GP.COLOR(""); );
  );

  M_BLOCK_THIN_TAB(
    "Thin Tab",
    GP.LABEL("Upload File/Folder");
    M_BOX(
      GP_CENTER,
      GP.FILE_UPLOAD("");
      GP.FOLDER_UPLOAD("");
    );
  );

  M_BOX(GP.LABEL("Select");   GP.SELECT("", "Some,Drop,List");  );
  M_BOX(GP.LABEL("Slider");   GP.SLIDER("");  );
  M_BOX(GP.LABEL("Spinner");  GP.SPINNER(""); );

  GP.BUTTON("", "Button");
  GP.BUTTON_MINI("", "Btn Mini");

  GP.BUILD_END();
}


void action() {
}

void setup()
{
  Serial.begin(115200);
  while (!Serial);

  Serial.print("\nStarting WebServer on " + String(ARDUINO_BOARD));
  Serial.println(" with " + String(SHIELD_TYPE));
  Serial.println(WEBSERVER_WT32_ETH01_VERSION);

  WT32_ETH01_onEvent();
  ETH.begin(ETH_PHY_ADDR, ETH_PHY_POWER);
  WT32_ETH01_waitForConnect();

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

void loop()
{
    ui.tick();
}
попробуйте, возможно заработает... насколько я понял webserver используется тот же, и по идее от смены интерфейса не должно завесить
 
  • Лойс +1
Реакции: kmarakov

SoftFelix

★✩✩✩✩✩✩
16 Фев 2020
48
12
Всем привет.

Для светодиода можно по UPDATE изменить не только состояние (вкл/выкл), но и цвет свечения?

GP.LED(имя, состояние, цвет); // + цвет из списка (см. GP. Цвета) (умолч. GP_GREEN) или цвет в формате PSTR("#rrggbb")

Т.е. чтобы один светодиод был не только вкл/выкл, но менял цвет (из доступных)? Такое, в принципе, возможно?
 

Sergo_ST

★★★★★★✩
15 Мар 2020
1,041
866
@SoftFelix, Для данного элемента такого функционала не предусмотрено.
Но можно реализовать с помощью небольшого JS скрипта и вызова его с необходимым цветом в ответ на обновление элемента EVAL.
 
  • Лойс +1
Реакции: SoftFelix

SoftFelix

★✩✩✩✩✩✩
16 Фев 2020
48
12
Но можно реализовать с помощью небольшого JS скрипта и вызова его с необходимым цветом в ответ на обновление элемента EVAL.
Я, к сожалению, ни-бэ-ни-мэ в этом. Если приведёте рабочий пример "что и как" - буду благодарен.
 

Sergo_ST

★★★★★★✩
15 Мар 2020
1,041
866
@SoftFelix, Вот пример кастомного индикатора с возможностью изменить цвет через update:
C++:
#define AP_SSID ""
#define AP_PASS ""

PGM_P colors[] = {GP_RED, GP_GREEN, GP_BLUE, GP_YELLOW}; //массив цветов для отправки

#include <GyverPortal.h>
GyverPortal ui;

String changeLedColor(const String& name, PGM_P st = "") {
  String str;
  str.reserve(100);
  str = F("ledColor('");
  str += name;
  str += F("','");
  str += FPSTR(st);
  str += F("')");
  return str;
}

void GP_LED_COLOR_SCRIPT(void) {
  GP.SEND(F("<script>function ledColor(id,cl){let el=getEl('led_'+id);if(el){if(cl){el.style.boxShadow='0px 0px 10px 2px '+cl;el.style.backgroundColor=cl;}else el.removeAttribute('style');}}</script>\n"));
  GP.SEND(F("<style>.ledc{width:20px;height:20px;border-radius:10px;display:inline-block;margin-bottom:-3px;background-color:#333;box-shadow:inset 0px 0px 5px 2px #0000005c;}</style>\n"));
}

void GP_LED_COLOR(const String& name, PGM_P st = GP_RED) {
  GP.SEND(F("<div name='led_"));
  GP.SEND(name);
  GP.SEND(F("' id='led_"));
  GP.SEND(name);
  GP.SEND(F("' class='ledc'></div>\n"));
  GP.JS_BEGIN();
  GP.SEND(changeLedColor(name, st));
  GP.JS_END();
  GP.EVAL(name);
}

void build() {
  GP_LED_COLOR_SCRIPT(); //скрипт, вызвать один раз в build()
  GP.BUILD_BEGIN();
  GP.THEME(GP_DARK);

  GP.TITLE("GyverPortal");
  GP.HR();

  M_BLOCK(
    GP.LABEL("Индикатор");
    GP_LED_COLOR("ledc", GP_RED); //индикатор, передать id для обновления и цвет
  );

  GP.UPDATE("ledc"); //добавдяем индикатор в список обновления
  GP.BUILD_END();
}

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());

  //подключаем конструктор и запускаем
  ui.attachBuild(build);
  ui.attach(action);
  ui.start();
}

void action() {
  if (ui.update()) {
    if (ui.update("ledc")) ui.answer(changeLedColor("ledc", GP_GREEN)); //если нужно изменить цвет индикатора, то в ответ отправляем id текущего обновляемого индикатора и новый цвет
    //if (ui.update("ledc")) ui.answer(changeLedColor("ledc", colors[random(0, 4)])); //или можно отправить цвет из предварительно объявленного массива цветов
    //if (ui.update("ledc")) ui.answer(changeLedColor("ledc")); //так-же можно выключить индикатор
  }
}

void loop() {
  ui.tick();
}
 
Изменено:
  • Лойс +1
Реакции: SoftFelix

SoftFelix

★✩✩✩✩✩✩
16 Фев 2020
48
12
@Sergo_ST, ух ты... Спасибо огромное!

Только сразу несколько (возможно глупых) вопросов:

1. Данная реализация LED'а, как я понял, не поддерживает полного отключения (только тёмный силуэт), как это сделано в штатном LED'е?
Сейчас я делаю так:
ui.updateBool("LED_G_NAME", LED_G_WEB); // где-то в программе меняется логическая LED_G_WEB (включаю-выключаю LED)

2. Не совсем понял (вернее совсем), как из внешней программы по событию менять цвет?
Сейчас у меня событие отлавливается через ui.updateBool, а как сейчас это делать? По id же это не сделаешь?
 

Sergo_ST

★★★★★★✩
15 Мар 2020
1,041
866
@SoftFelix, 1. Передать можно любой цвет, в тч и в виде строки. В стоковых ледах отключенное состояние имеет цвет #333.
C++:
if (ui.update("LED_G_NAME")) ui.answer(changeLedColor("LED_G_NAME", "#333"));
2. Во время ответа считываете состояние своей переменной и отправляете нужный цвет(или не отвечаете на update если изменение цвета не требуется).
C++:
if (ui.update("LED_G_NAME")) ui.answer(changeLedColor("LED_G_NAME", LED_G_WEB?GP_GREEN:"#333"));
Так-же можно создать массив необходимых цветов, и отправлять нужный в зависимости от состояния какой-либо переменной.
C++:
PGM_P colors[] = {GP_RED, GP_GREEN, GP_BLUE, GP_YELLOW}; //массив цветов для отправки
if (ui.update("LED_G_NAME")) ui.answer(changeLedColor("LED_G_NAME", colors[LED_G_WEB]));

Пс. Обновил скрипт, если в update не передавать цвет или передать пустую строку(""), то будет включен стиль "выключенного индикатора".
C++:
if (ui.update("LED_G_NAME")) ui.answer(changeLedColor("LED_G_NAME"));
 
Изменено:
  • Лойс +1
Реакции: SoftFelix

Doctor Death

✩✩✩✩✩✩✩
16 Мар 2025
16
0
Коллеги, подскажите, не могу понять с цветами индикатора GP.LED , вроде по описанию дефолтный должен быть зеленый , но не зеленый, а белы , а выключенный серый
причем при GP.LED_GREEN, тот же набор цветов
как включённый индикатор сделать зеленым?
 

Sergo_ST

★★★★★★✩
15 Мар 2020
1,041
866
@Doctor Death, Как и с казал @Bruzzer, это проблема проявляется в браузерах Firefox, если хотите чтоб лед-ы отображались везде одинаково, можете использовать пример кастомного лед-а, который я приводил выше в посте 891.
 
  • Лойс +1
Реакции: SoftFelix и Doctor Death

SoftFelix

★✩✩✩✩✩✩
16 Фев 2020
48
12
Как и с казал @Bruzzer, это проблема проявляется в браузерах Firefox
А можно чуть подробнее, почему так происходит? И можно ли простыми действиями доработать штатные LED'ы в GP, что бы они нормально отображались и в FF?.