#include "config.h" #ifdef HTTP_SERVER_ENABLE #include "http_server.h" #include "effects.h" #include "my_wifi.h" #include "functions.h" #include "prototypes.h" #include AsyncWebServer http_server(HTTP_SERVER_PORT); AsyncWebSocket ws("/ws"); uint32_t monitor_client = 0; void http_server_handle_file_upload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final) { File upload_file; if (index == 0) { // Start of upload LOGln("HTTP * Upload of %s starting...", filename.c_str()); upload_file = SPIFFS.open(filename, "w"); } else { upload_file = SPIFFS.open(filename, "a"); } upload_file.write(data, len); if (final) { LOGln("HTTP * Upload of %s done.", filename.c_str()); } } void ws_send_effects(AsyncWebSocketClient* client) { String msg = "{\"effects\": ["; for (int i=0; i0) msg += ", "; msg += '"'; msg += effects[i].name; msg += '"'; } msg += "]}"; client->text(msg); } void ws_send_settings(AsyncWebSocketClient* client) { String msg = "{\"settings\": ["; for (int i=0; i0) msg += ", "; msg += "{\"name\":\""; msg += all_settings[i].name; msg += "\",\"value\":"; msg += *(all_settings[i].value); msg += ",\"type\":\""; switch (all_settings[i].type) { case TYPE_UINT8: msg += "uint8"; break; case TYPE_UINT16: msg += "uint16"; break; case TYPE_BOOL: msg += "bool"; break; default: msg += "unknown"; } msg += "\"}"; } msg += "]}"; client->text(msg); } void ws_set_setting(String s) { int8_t index = s.indexOf(":"); if (index < 1) return; String key = s.substring(0, index); String value = s.substring(index+1); change_setting(key.c_str(), value.toInt()); } void handle_ws(AsyncWebSocket* server, AsyncWebSocketClient* client, AwsEventType type, void* arg, uint8_t* data, size_t len) { if (type == WS_EVT_CONNECT) { LOGln("Websocket * Client connected. ID: %d", client->id()); } else if (type == WS_EVT_DISCONNECT) { if (monitor_client == client->id()) monitor_client=0; LOGln("Websocket * Client disconnected."); } else if (type == WS_EVT_DATA) { AwsFrameInfo* info = (AwsFrameInfo*)arg; if (info->opcode == WS_TEXT) { data[len] = 0; String msg = String((char*)data); LOGln("Websocket * In: %s", msg.c_str()); if (msg.startsWith("effect:")) { change_current_effect(msg.substring(7)); } else if (msg.equals("effects?")) { ws_send_effects(client); } else if (msg.equals("settings?")) { ws_send_settings(client); } else if (msg.startsWith("setting:")) { ws_set_setting(msg.substring(8)); } else if (msg.equals("monitor:1")) { monitor_client = client->id(); } else if (msg.equals("monitor:0")) { if (monitor_client == client->id()) monitor_client=0; } else { client->text("Unknown command. Accepted commands:\neffects?\nsettings?\nsetting::\neffect:\nmonitor:<0/1>"); } } } } void http_server_setup() { static const char* PROGMEM text_plain = "text/plain"; http_server.on("/", HTTP_GET, [&](AsyncWebServerRequest* request){ LOGln("HTTP * GET /"); String response = String(F("Pitrix

Pitrix

Settings

Effect

Known animations:

")); if (!SPIFFS.begin()) { response += F("No SPIFFS file system found."); } else { response += F("
    "); Dir dir = SPIFFS.openDir("/"); while (dir.next()) { char buffer[100]; snprintf_P(buffer, 100, PSTR("
  • %s (delete)
  • "), dir.fileName().c_str(), dir.fileName().c_str()); response += buffer; } response += F("
"); response += F("
"); } response += F(""); request->send(200, "text/html", response); }); http_server.on("/settings", HTTP_GET, [&](AsyncWebServerRequest* request) { String message = F("Pitrix settings

Pitrix settings

Back to main page\n"); for (int i=0; i\n"); } message += F("
"); if (default_value != value) { message += F(""); } message += s.name; if (default_value != value) { message += F(""); } message += F(""); message += value; if (default_value != value) { message += " ("; message += default_value; message += ")"; } char buffer[150]; snprintf_P(buffer, 150, PSTR("
"), s.name); message += buffer; if (s.type==TYPE_UINT8 || s.type==TYPE_UINT16) { snprintf_P(buffer, 150, PSTR(""), value, s.type==TYPE_UINT8 ? 255 : 65535); } else if (s.type==TYPE_BOOL) { snprintf_P(buffer, 150, PSTR(" Off / On"), value==0?"checked":"", value==1?"checked":""); } message += buffer; message += F("
"); request->send(200, "text/html", message); }); http_server.on("/settings", HTTP_POST, [&](AsyncWebServerRequest* request) { if (!request->hasParam("key", true) || !request->hasParam("value", true)) { request->send(400, "text/plain", "Missing argument."); return; } String name = request->getParam("key", true)->value(); uint16_t value = request->getParam("value", true)->value().toInt(); if (change_setting(name.c_str(), value)) { if (request->hasParam("redir")) { request->redirect("/settings"); } else { request->send(200, "text/plain", "OK"); } save_settings(); } else { request->send(400, "text/plain", "Could not change setting."); } }); http_server.on("/settings/load", HTTP_POST, [&](AsyncWebServerRequest* request) { load_settings(); request->send(200, "text/plain", "OK"); }); http_server.on("/settings/save", HTTP_POST, [&](AsyncWebServerRequest* request) { save_settings(); request->send(200, "text/plain", "OK"); }); http_server.on("/settings.txt", HTTP_GET, [&](AsyncWebServerRequest* request) { File f; if (SPIFFS.begin()) { f=SPIFFS.open("/pitrix_settings.txt", "r"); if (f) { String s = f.readString(); f.close(); request->send(200, "text/plain", s); return; } } request->send(500, "text/plain", "Could not read settings."); }); http_server.on("/effects", HTTP_GET, [&](AsyncWebServerRequest* request) { String message = F("Pitrix effects

Pitrix settings

Back to main page"); char buffer[500]; for (int i=0; i"), effects[i].name, effects[i].name); message += buffer; } message += F("
%s
"); request->send(200, "text/html", message); }); http_server.on("/effects", HTTP_POST, [&](AsyncWebServerRequest* request) { if (!request->hasParam("name", true)) { request->send(400, "text/plain", "Missing argument 'name'."); return; } String name = request->getParam("name", true)->value(); if (change_current_effect(name)) { if (request->hasParam("redir")) { request->redirect("/effects"); } else { request->send(200, "text/plain", "OK"); } } else { request->send(404, "text/plain", "Effect not found."); } }); http_server.on("/delete", HTTP_GET, [&](AsyncWebServerRequest* request) { LOGln("HTTP * GET /delete"); if (request->params()==0) { request->send_P(400, text_plain, PSTR("No filename given")); return; } String file = request->getParam(0)->value(); if (file == "/") { request->send_P(400, text_plain, PSTR("Invalid path")); return; } if (!SPIFFS.exists(file)) { request->send_P(400, text_plain, PSTR("File does not exist.")); return; } SPIFFS.remove(file); request->send_P(200, text_plain, PSTR("OK")); }); http_server.on("/upload", HTTP_POST, [](AsyncWebServerRequest* request) { request->send(200); }, http_server_handle_file_upload); http_server.on("/free_heap", HTTP_GET, [&](AsyncWebServerRequest* request){ LOGln("HTTP * GET /free_heap"); request->send(200, "text/plain", String(ESP.getFreeHeap())); }); http_server.on("/uptime", HTTP_GET, [&](AsyncWebServerRequest* request){ LOGln("HTTP * GET /uptime"); request->send(200, "text/plain", String(millis()/1000)); }); http_server.on("/fps", HTTP_GET, [](AsyncWebServerRequest* request){ LOGln("HTTP * GET /fps"); request->send(200, "text/plain", String(FastLED.getFPS())); }); http_server.on("/reboot", HTTP_POST, [](AsyncWebServerRequest* request){ LOGln("HTTP * POST /reboot"); ESP.restart(); }); http_server.on("/mode", HTTP_POST, [&](AsyncWebServerRequest* request){ LOGln("HTTP * POST /mode with value %s", request->getParam("plain", true)->value().c_str()); if (!request->hasParam("plain", true)) { request->send_P(400, text_plain, PSTR("No effect given.")); return; } String val = request->getParam("plain", true)->value(); if (change_current_effect(val)) { request->send(200, "text/plain", "OK"); } else { request->send_P(400, text_plain, PSTR("Unknown effect.")); } }); http_server.on("/monitor", HTTP_GET, [&](AsyncWebServerRequest* request) { static const char* html PROGMEM = R"( Pitrix

)"; request->send_P(200, PSTR("text/html"), html); }); ws.onEvent(handle_ws); http_server.addHandler(&ws); http_server.begin(); MDNS.addService("_http", "_tcp", 80); } void http_server_send_framedata() { if (ws.count()>0 && monitor_client>0) { if (ws.hasClient(monitor_client)) { uint16_t _size = LED_WIDTH * LED_HEIGHT * 3 + 4; uint8_t* _buffer = new uint8_t[_size]; _buffer[0] = LED_WIDTH; _buffer[1] = LED_HEIGHT; _buffer[2] = 255; for (uint8_t y=0; y