You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

271 lines
11 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// базовый пример работы с библиотекой, основные возможности. Загрузи и изучай код
// логин-пароль от роутера
#define AP_SSID "Alex"
#define AP_PASS "alexpass"
#include <Arduino.h>
#include <GyverHub.h>
GyverHub hub;
// GyverHub hub("MyDevices", "ESP", ""); // можно настроить тут, но без F-строк!
// обработчик кнопки (см. ниже)
void btn_cb() {
Serial.println("click 4");
}
// обработчик кнопки с информацией о билде (см. ниже)
void btn_cb_b(gh::Build& b) {
Serial.print("click 5 from client ID: ");
Serial.println(b.client.id);
}
// билдер
void build(gh::Builder& b) {
// =================== КОНТЕЙНЕРЫ ===================
// основной контейнер страницы - столбец, т.е. виджеты будут располагаться на новых строках
b.Button();
b.Button();
// СПОСОБ 1
// вот так можно сделать горизонтальный контейнер
b.beginRow(); // начать
b.Button();
b.Button();
b.endRow(); // ВАЖНО НЕ ЗАБЫТЬ ЕГО ЗАВЕРШИТЬ
// СПОСОБ 2
// для красоты и удобства можно обернуть контейнер в блок {}
// функции beginRow() и beginCol() всегда возвращают true
if (b.beginRow()) {
b.Button();
b.Button();
b.endRow(); // завершить
}
// СПОСОБ 3
// есть ещё такой трюк - контейнер сам себя закроет в рамках блока {}
// назвать его можно как угодно, передать во внутрь аргумент билдера
{
gh::Row r(b); // контейнер сам создастся здесь
b.Button();
b.Button();
} // контейнер сам закроется здесь
// СПОСОБ 4
// и ещё вот такой макрос. Ширина контейнера 1 по умолчанию
GH_ROW(b, 1,
b.Button();
b.Button(););
// для вертикального контейнера справедлив такой же синтаксис:
// beginCol(), endCol(), gh::Col(), GH_COL()
// =================== ШИРИНА ===================
// ширина виджетов задаётся в "долях" - отношении их ширины друг к другу
// виджеты займут пропорциональное место во всю ширину контейнера
// если ширина не указана - она принимается за 1
{
gh::Row r(b);
b.Slider().size(3); // слайдер шириной 3
b.Button().size(1); // кнопка шириной 1
b.Button(); // тоже 1
b.Button();
}
// посмотрим, как работает задание ширины контейнеру
{
gh::Row r(b);
{
// этот контейнер будет в 2 раза шире...
gh::Row r(b, 2);
b.Button();
b.Button();
}
{
// ...чем этот
gh::Row r(b, 1);
b.Button();
b.Button();
}
}
// =================== ПАРАМЕТРЫ ВИДЖЕТА ===================
if (b.beginRow()) {
// параметры виджета можно задавать цепочкой. Например:
b.Button().label(F("my button 1")).color(gh::Colors::Red);
// также можно продолжить настраивать ПРЕДЫДУЩИЙ виджет, обратившись к widget:
b.Button(); // кнопка без параметров
b.widget.label(F("my button 2")); // настраиваем кнопку выше
b.widget.color(gh::Colors::Blue); // её же
b.endRow();
}
// =================== ДЕЙСТВИЯ ВИДЖЕТА ===================
// с активных виджетов можно получить сигнал о действии - клик или изменение значения
if (b.beginRow()) {
// СПОСОБ 1
// проверить условие click() - он вернёт true при действии
// click() нужно вызывать ПОСЛЕДНИМ в цепочке!!!
if (b.Button().click()) Serial.println("click 1");
// СПОСОБ 2
// подключить bool переменную - флаг
bool flag = 0;
b.Button().attach(&flag);
if (flag) Serial.println("click 2");
// СПОСОБ 3
// подключить gh::Flag переменную - флаг
// данный флаг сам сбросится в false при проверке!
gh::Flag gflag;
b.Button().attach(&gflag);
if (gflag) Serial.println("click 3");
// здесь gflag уже false
// СПОСОБ 4
// подключить функцию-обработчик (см. выше)
b.Button().attach(btn_cb);
// СПОСОБ 5
// подключить функцию-обработчик с инфо о билде (см. выше)
b.Button().attach(btn_cb_b);
// attach() может быть НЕ ПОСЛЕДНИМ в цепочке, также их может быть несколько:
// b.Button().attach(f1).attach(f2).label("kek");
b.endRow();
}
// =============== ПОДКЛЮЧЕНИЕ ПЕРЕМЕННОЙ ===============
if (b.beginRow()) {
// библиотека позволяет подключить к активному виджету переменную для чтения и записи
// я создам статические переменные для ясности. Они могут быть глобальными и так далее
// таким образом изменения останутся при перезагрузке страницы
static int sld;
static String inp;
static bool sw;
// для подключения нужно передать переменную по адресу
// библиотека сама определит тип переменной и будет брать из неё значение и записывать при действиях
// библиотека поддерживает все стандартные типы данных, а также некоторые свои (Pairs, Pos, Button, Log...)
b.Slider(&sld).size(2);
b.Input(&inp).size(2);
// внутри обработки действия переменная уже будет иметь новое значение:
if (b.Switch(&sw).size(1).click()) {
Serial.print("switch: ");
Serial.println(sw);
}
b.endRow();
}
// ==================== ОБНОВЛЕНИЕ ====================
// библиотека позволяет обновлять значения на виджетах. Это можно делать
// - из основной программы (см. ниже)
// - из билдера - но только при действиях по виджетам!
// для отправки обновления нужно знать ИМЯ компонента. Его можно задать почти у всех виджетов
// к функции добавляется подчёркивание, всё остальное - как раньше
if (b.beginRow()) {
b.Label_(F("label")).size(2).value("default"); // с указанием стандартного значения
if (b.Button().size(1).click()) {
hub.update(F("label")).value(random(100, 500));
}
b.endRow();
}
// в самом низу сделаем заголовок, текст будем обновлять из loop() (см. ниже)
b.Title_(F("title"));
// =================== ИНФО О БИЛДЕ ===================
// можно получить информацию о билде и клиенте для своих целей
// поставь тут 1, чтобы включить вывод =)
if (0) {
// запрос информации о виджетах
if (b.build.isUI()) {
Serial.println("=== UI BUILD ===");
}
// действие с виджетом
if (b.build.isSet()) {
Serial.println("=== SET ===");
Serial.print("name: ");
Serial.println(b.build.name);
Serial.print("value: ");
Serial.println(b.build.value);
}
Serial.print("client from: ");
Serial.println(gh::readConnection(b.build.client.connection()));
Serial.print("ID: ");
Serial.println(b.build.client.id);
Serial.println();
}
}
void setup() {
Serial.begin(115200);
#ifdef GH_ESP_BUILD
// подключение к роутеру
WiFi.mode(WIFI_STA);
WiFi.begin(AP_SSID, AP_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println(WiFi.localIP());
// если нужен MQTT - подключаемся
hub.mqtt.config("test.mosquitto.org", 1883);
// hub.mqtt.config("test.mosquitto.org", 1883, "login", "pass");
// ИЛИ
// режим точки доступа
// WiFi.mode(WIFI_AP);
// WiFi.softAP("My Hub");
// Serial.println(WiFi.softAPIP()); // по умолч. 192.168.4.1
#endif
// указать префикс сети, имя устройства и иконку
hub.config(F("MyDevices"), F("ESP"), F(""));
// подключить билдер
hub.onBuild(build);
// запуск!
hub.begin();
}
void loop() {
// =================== ТИКЕР ===================
// вызываем тикер в главном цикле программы
// он обеспечивает работу связи, таймаутов и прочего
hub.tick();
// =========== ОБНОВЛЕНИЯ ПО ТАЙМЕРУ ===========
// в библиотеке предусмотрен удобный класс асинхронного таймера
static gh::Timer tmr(1000); // период 1 секунда
// каждую секунду будем обновлять заголовок
if (tmr) {
hub.update(F("title")).value(millis());
}
}