#include <Arduino.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>
#define NUM_PTR_FUN 3
const uint8_t interval_1 = 50; //ms.
const uint16_t interval_2 = 500; //ms.
uint32_t timer_1 = 0;
uint32_t timer_2 = 0;
uint32_t freeHeap = 0;
bool sendFreeHeap = false;
bool needToUpdateStates = false;
IPAddress ipAP{192, 168, 4, 1};
AsyncWebServer server(80);
AsyncWebSocket ws1("/ws");
// Отправка состояний кнопок (GPIO)
void sendStates(AsyncWebSocketClient * client = NULL) {
StaticJsonDocument<200> jsonDoc; // создаем буфер
JsonArray root = jsonDoc.to<JsonArray>(); //создаем ссылку на массив
root.add(0); // добавляем элемент в корневой массив
JsonArray states = root.createNestedArray(); // создаем ссылку на вложенный массив
states.add(digitalRead(0)); // и добавляем туда данные
states.add(digitalRead(2));
states.add(digitalRead(4));
states.add(digitalRead(5));
size_t len = measureJson(root); // записываем длину массива
AsyncWebSocketMessageBuffer * buffer = ws1.makeBuffer(len); // создаем буфер для отправки данных
if (buffer) {
serializeJson(root, (char *)buffer->get(), len + 1); // если буфер успешно создан то записывем туда данные
if (client) {
client->text(buffer); // если клиент указан то отправляем содержимое буфера клиенту
} else {
ws1.textAll(buffer); // если клиент не указан то отправляем содержимое буфера всем подключеным клиентам
}
}
}
// Обработчик управления GPIO с веб интерфейса
void H_pinChange(JsonVariant payload, AsyncWebSocketClient * client) {
digitalWrite(payload, !digitalRead(payload));
needToUpdateStates = true;
}
// Обработчик управления free heap с веб интерфейса
void H_freeHeap(JsonVariant payload, AsyncWebSocketClient * client) {
sendFreeHeap = payload;
}
// Обработчик управления получения ID с веб интерфейса
void H_getChipId(JsonVariant payload, AsyncWebSocketClient * client) {
StaticJsonDocument<50> jsonDoc;
JsonArray root = jsonDoc.to<JsonArray>();
root.add(payload);
root.add(ESP.getChipId());
size_t len = measureJson(root);
AsyncWebSocketMessageBuffer * buffer = ws1.makeBuffer(len);
if (buffer) {
serializeJson(root, (char *)buffer->get(), len + 1);
client->text(buffer);
}
}
// массив указателей на функции обработчиков
void (*arrFnPtr[NUM_PTR_FUN])(JsonVariant payload, AsyncWebSocketClient * client) = {
H_pinChange, // [0] - управление GPIO
H_freeHeap, // [1] - отправлять free heap (да\нет)
H_getChipId // [2] - получить ID
// дальше можно дописывать для добавления новых обработчиков, при этом необходимо увеличить NUM_PTR_FUN до нужного размера
};
// Парсер входящих ws сообщений
// Число в первой ячейке массива(root[0]), является индексом указателя на функцию
// таким образом парсер определяет какую функцию-обработчик использовать
void readJsonData(const char *data, AsyncWebSocketClient * client) {
Serial.printf("from ws data: %s client: %u\n", data, client->id());
DynamicJsonDocument jsonDoc(1024);
auto error = deserializeJson(jsonDoc, data);
JsonArray root = jsonDoc.as<JsonArray>();
if (!error) {
arrFnPtr[root[0].as<uint8_t>()](root[1].as<JsonVariant>(), client);
}
}
// Приемник ws сообщений (упрощенный на 1 фрейм)
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len) {
if (type == WS_EVT_CONNECT) {
Serial.printf("client id: %u connected\n", client->id());
sendStates(client);
} else if (type == WS_EVT_DATA) {
AwsFrameInfo * info = (AwsFrameInfo*)arg;
data[info->len] = '\0';
readJsonData((char*)data, client);
} else if (type == WS_EVT_DISCONNECT) {
//client disconnected
os_printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
} else if (type == WS_EVT_ERROR) {
//error was received from the other end
os_printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
}
}
// Обработчик несуществующей страницы
void notFound(AsyncWebServerRequest *request) {
request->send(404, "text/plain", "Not found");
}
// Инициализация сервера
void serverInit() {
ws1.onEvent(onWsEvent);
server.addHandler(&ws1);
server.serveStatic("/", SPIFFS, "/").setCacheControl("max-age=31536000");
server.onNotFound(notFound);
server.begin();
}
// Инициализация wifi сети
void wifiInit() {
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(ipAP, ipAP, IPAddress(255, 255, 255, 0));
WiFi.softAP("espAP", "");
}
void setup() {
Serial.begin(115200);
Serial.println();
pinMode(0, OUTPUT);
pinMode(2, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
SPIFFS.begin();
wifiInit();
serverInit();
}
void loop() {
if (millis() > timer_1) {
timer_1 = millis() + interval_1;
if (needToUpdateStates) {
sendStates();
needToUpdateStates = false;
}
}
yield();
if (millis() > timer_2) {
timer_2 = millis() + interval_2;
ws1.printfAll("[3,%lu]", millis());
if (sendFreeHeap) {
freeHeap = ESP.getFreeHeap();
ws1.printfAll("[1,%u]", freeHeap);
}
}
yield();
}