/* ESPurna WEBSERVER MODULE Copyright (C) 2016 by Xose PĂ©rez */ #include #include #include #include #include #include #include AsyncWebServer server(80); AsyncWebSocket ws("/ws"); unsigned long _csrf[CSRF_BUFFER_SIZE]; // ----------------------------------------------------------------------------- // WEBSOCKETS // ----------------------------------------------------------------------------- bool webSocketSend(char * payload) { //DEBUG_MSG("[WEBSOCKET] Broadcasting '%s'\n", payload); ws.textAll(payload); } bool webSocketSend(uint32_t client_id, char * payload) { //DEBUG_MSG("[WEBSOCKET] Sending '%s' to #%ld\n", payload, client_id); ws.text(client_id, payload); } void webSocketParse(uint32_t client_id, uint8_t * payload, size_t length) { // Parse JSON input DynamicJsonBuffer jsonBuffer; JsonObject& root = jsonBuffer.parseObject((char *) payload); if (!root.success()) { DEBUG_MSG("[WEBSOCKET] Error parsing data\n"); ws.text(client_id, "{\"message\": \"Error parsing data!\"}"); return; } // CSRF unsigned long csrf = 0; if (root.containsKey("csrf")) csrf = root["csrf"]; if (csrf != _csrf[client_id % CSRF_BUFFER_SIZE]) { DEBUG_MSG("[WEBSOCKET] CSRF check failed\n"); ws.text(client_id, "{\"message\": \"Session expired, please reload page...\"}"); return; } // Check actions if (root.containsKey("action")) { String action = root["action"]; DEBUG_MSG("[WEBSOCKET] Requested action: %s\n", action.c_str()); if (action.equals("reset")) ESP.reset(); if (action.equals("reconnect")) wifiDisconnect(); if (action.equals("on")) switchRelayOn(); if (action.equals("off")) switchRelayOff(); }; // Check config if (root.containsKey("config") && root["config"].is()) { JsonArray& config = root["config"]; DEBUG_MSG("[WEBSOCKET] Parsing configuration data\n"); bool dirty = false; bool dirtyMQTT = false; unsigned int network = 0; for (unsigned int i=0; iid()); DEBUG_MSG("[WEBSOCKET] #%u connected, ip: %d.%d.%d.%d, url: %s\n", client->id(), ip[0], ip[1], ip[2], ip[3], server->url()); } #endif webSocketStart(client->id()); } else if(type == WS_EVT_DISCONNECT) { DEBUG_MSG("[WEBSOCKET] #%u disconnected\n", client->id()); } else if(type == WS_EVT_ERROR) { DEBUG_MSG("[WEBSOCKET] #%u error(%u): %s\n", client->id(), *((uint16_t*)arg), (char*)data); } else if(type == WS_EVT_PONG) { DEBUG_MSG("[WEBSOCKET] #%u pong(%u): %s\n", client->id(), len, len ? (char*) data : ""); } else if(type == WS_EVT_DATA) { webSocketParse(client->id(), data, len); } } // ----------------------------------------------------------------------------- // WEBSERVER // ----------------------------------------------------------------------------- void onHome(AsyncWebServerRequest *request) { DEBUG_MSG("[WEBSERVER] Request: %s\n", request->url().c_str()); String password = getSetting("adminPass", ADMIN_PASS); char httpPassword[password.length() + 1]; password.toCharArray(httpPassword, password.length() + 1); if (!request->authenticate(HTTP_USERNAME, httpPassword)) { return request->requestAuthentication(); } request->send(SPIFFS, "/index.html"); } void onRelayOn(AsyncWebServerRequest *request) { DEBUG_MSG("[WEBSERVER] Request: %s\n", request->url().c_str()); switchRelayOn(); request->send(200, "text/plain", "ON"); }; void onRelayOff(AsyncWebServerRequest *request) { DEBUG_MSG("[WEBSERVER] Request: %s\n", request->url().c_str()); switchRelayOff(); request->send(200, "text/plain", "OFF"); }; void webSetup() { // Setup websocket plugin ws.onEvent(webSocketEvent); server.addHandler(&ws); // Serve home (password protected) server.on("/", HTTP_GET, onHome); server.on("/index.html", HTTP_GET, onHome); // API entry points (non protected) server.on("/relay/on", HTTP_GET, onRelayOn); server.on("/relay/off", HTTP_GET, onRelayOff); // Serve static files server.serveStatic("/", SPIFFS, "/"); // 404 server.onNotFound([](AsyncWebServerRequest *request){ request->send(404); }); // Run server server.begin(); }