#include <Arduino.h>
#include <WiFi.h>
#include <SPIFFS.h>
#include <FS.h>
#include <Preferences.h>
#include <ESP32Ping.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>
#include "esp_system.h"
#include "esp_task_wdt.h"
#include <esp_timer.h>
#include <driver/adc.h>
#define MAX_COMMAND_LEN 128
#define MAX_HISTORY_LEN 10
Preferences preferences;
String currentDir = "/";
char commandHistory[MAX_HISTORY_LEN][MAX_COMMAND_LEN];
int historyIndex = 0;
int historyCount = 0;
char input[MAX_COMMAND_LEN];
size_t len = 0;
void setup();
void loop();
void displaySystemInfo();
void scanWiFiNetworks();
void connectToWiFi(const char* ssid, const char* password);
void disconnectWiFi();
void loadWiFiCredentials();
void saveWiFiCredentials(const char* ssid, const char* password);
void listFiles();
void changeDirectory(const char* dirName);
void showFileContents(const char* filename);
void createFile(const char* filename);
void createDirectory(const char* dirName);
void deleteFileOrDirectory(const char* name);
void renameFile(const char* oldName, const char* newName);
void moveFile(const char* src, const char* dest);
void displayHelp();
void pingCommand(const char* address, int count);
void ifconfigCommand();
void memoryInfoCommand();
void fetchmeCommand();
void rebootCommand();
void uptimeCommand();
void freeMemCommand();
void handleCommand(char* input);
void addToHistory(const char* command);
void showCommandHistory();
void completeCommand(char* input);
void handleHelpFlag(const char* command);
struct Command {
const char* name;
void (*func)(const char* arg1, const char* arg2);
const char* help;
};
Command commands[] = {
{"help", [](const char* arg1, const char* arg2) { displayHelp(); }, "Display help information"},
{"ls", [](const char* arg1, const char* arg2) { listFiles(); }, "List files in a directory"},
{"cd", [](const char* arg1, const char* arg2) { changeDirectory(arg1); }, "Change directory"},
{"cat", [](const char* arg1, const char* arg2) { showFileContents(arg1); }, "Display file contents"},
{"touch", [](const char* arg1, const char* arg2) { createFile(arg1); }, "Create a new file"},
{"mkdir", [](const char* arg1, const char* arg2) { createDirectory(arg1); }, "Create a new directory"},
{"rm", [](const char* arg1, const char* arg2) { deleteFileOrDirectory(arg1); }, "Remove file or directory"},
{"rename", [](const char* arg1, const char* arg2) { renameFile(arg1, arg2); }, "Rename a file"},
{"mv", [](const char* arg1, const char* arg2) { moveFile(arg1, arg2); }, "Move a file"},
{"wifi_scan", [](const char* arg1, const char* arg2) { scanWiFiNetworks(); }, "Scan for WiFi networks"},
{"wifi_connect", [](const char* arg1, const char* arg2) { connectToWiFi(arg1, arg2); }, "Connect to a WiFi network"},
{"wifi_disconnect", [](const char* arg1, const char* arg2) { disconnectWiFi(); }, "Disconnect from WiFi"},
{"ping", [](const char* arg1, const char* arg2) { pingCommand(arg1, atoi(arg2)); }, "Ping an IP address or domain"},
{"ifconfig", [](const char* arg1, const char* arg2) { ifconfigCommand(); }, "Display network configuration"},
{"meminfo", [](const char* arg1, const char* arg2) { memoryInfoCommand(); }, "Display memory information"},
{"fetchme", [](const char* arg1, const char* arg2) { fetchmeCommand(); }, "Display system information like neofetch"},
{"reboot", [](const char* arg1, const char* arg2) { rebootCommand(); }, "Reboot the system"},
{"uptime", [](const char* arg1, const char* arg2) { uptimeCommand(); }, "Display system uptime"},
{"free_mem", [](const char* arg1, const char* arg2) { freeMemCommand(); }, "Display free memory"}
};
void setup() {
Serial.begin(115200);
if (!SPIFFS.begin(true)) {
Serial.println("SPIFFS Mount Failed");
return;
}
preferences.begin("wifi", false);
displaySystemInfo();
loadWiFiCredentials();
Serial.print("> ");
}
void loop() {
if (Serial.available() > 0) {
char ch = Serial.read();
if (ch == '\n' || ch == '\r') {
input[len] = '\0';
Serial.println();
handleCommand(input);
len = 0;
Serial.print("> ");
} else if (ch == '\t') {
completeCommand(input);
} else if (ch == 0x1B) { // Handle arrow keys
if (Serial.available() > 0 && Serial.read() == '[') {
char arrow = Serial.read();
if (arrow == 'A') { // Up arrow
if (historyCount > 0) {
historyIndex = (historyIndex + historyCount - 1) % historyCount;
strcpy(input, commandHistory[historyIndex]);
len = strlen(input);
Serial.print("\r> ");
Serial.print(input);
}
} else if (arrow == 'B') { // Down arrow
if (historyCount > 0) {
historyIndex = (historyIndex + 1) % historyCount;
strcpy(input, commandHistory[historyIndex]);
len = strlen(input);
Serial.print("\r> ");
Serial.print(input);
}
}
}
} else if (len < MAX_COMMAND_LEN - 1) {
input[len++] = ch;
Serial.print(ch);
}
}
}
void displaySystemInfo() {
Serial.println("\033[1;34mESP32 System Information:\033[0m");
Serial.printf(" \033[1;32mSDK Version:\033[0m %s\n", ESP.getSdkVersion());
Serial.printf(" \033[1;32mFree Heap:\033[0m %d bytes\n", ESP.getFreeHeap());
Serial.printf(" \033[1;32mCPU Frequency:\033[0m %d MHz\n", ESP.getCpuFreqMHz());
Serial.println(" \033[1;32mType 'help' to see the list of available commands.\033[0m");
Serial.print("> ");
}
void scanWiFiNetworks() {
Serial.println("\033[1;33mScanning for WiFi networks...\033[1;0m");
const char spinner[] = {'|', '/', '-', '\\'};
int spinnerIndex = 0;
for (int i = 0; i < 30; ++i) {
Serial.print(spinner[spinnerIndex]);
delay(100);
Serial.print("\b");
spinnerIndex = (spinnerIndex + 1) % 4;
}
Serial.println();
int numNetworks = WiFi.scanNetworks();
for (int i = 0; i < numNetworks; ++i) {
Serial.printf("%d: %s (%d dBm)\n", i + 1, WiFi.SSID(i).c_str(), WiFi.RSSI(i));
}
if (numNetworks == 0) {
Serial.println("No networks found.");
Serial.println();
Serial.print("> ");
return;
}
Serial.println("\nType the number of the network you want to connect to:");
while (Serial.available() == 0) {
delay(10);
}
int selectedNetwork = Serial.parseInt();
Serial.read(); // Clear the newline character from the buffer
if (selectedNetwork < 1 || selectedNetwork > numNetworks) {
Serial.println("Invalid selection.");
Serial.println();
Serial.print("> ");
return;
}
String selectedSSID = WiFi.SSID(selectedNetwork - 1);
String savedPassword = preferences.getString(selectedSSID.c_str(), "");
if (savedPassword.length() > 0) {
Serial.println("Trying saved credentials...");
connectToWiFi(selectedSSID.c_str(), savedPassword.c_str());
} else {
bool connected = false;
while (!connected) {
Serial.println("Enter the password for the network:");
while (Serial.available() == 0) {
delay(10);
}
String password = Serial.readStringUntil('\n');
password.trim();
connectToWiFi(selectedSSID.c_str(), password.c_str());
if (WiFi.status() == WL_CONNECTED) {
Serial.println("Connected successfully!");
saveWiFiCredentials(selectedSSID.c_str(), password.c_str());
connected = true;
} else {
Serial.println("Failed to connect. Please check the password and try again.");
Serial.println("Would you like to try again? (\033[1;92mY\033[1;0m/\033[1;91mN\033[1;0m):");
while (Serial.available() == 0) {
delay(10);
}
String retry = Serial.readStringUntil('\n');
retry.trim();
retry.toLowerCase();
if (retry != "y" && retry != "yes") {
connected = true; // Exit the loop if user does not want to try again
}
}
}
}
Serial.println();
Serial.print("> ");
}
void connectToWiFi(const char* ssid, const char* password) {
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi...");
unsigned long startAttemptTime = millis();
const unsigned long timeout = 10000; // 10 seconds timeout
while (WiFi.status() != WL_CONNECTED && millis() - startAttemptTime < timeout) {
Serial.print(".");
delay(500);
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("Connected!");
} else {
Serial.println("Failed to connect within the timeout period.");
if (preferences.getString(ssid, "").length() > 0) {
Serial.println("Saved credentials may be outdated or incorrect.");
}
}
Serial.println();
Serial.print("> ");
}
void disconnectWiFi() {
WiFi.disconnect();
Serial.println("Disconnected from WiFi.");
Serial.println();
Serial.print("> ");
}
void loadWiFiCredentials() {
String ssid = preferences.getString("ssid", "");
String password = preferences.getString("password", "");
if (ssid.length() > 0 && password.length() > 0) {
WiFi.begin(ssid.c_str(), password.c_str());
}
}
void saveWiFiCredentials(const char* ssid, const char* password) {
preferences.putString("ssid", ssid);
preferences.putString("password", password);
}
void listFiles() {
File root = SPIFFS.open(currentDir);
if (!root) {
Serial.println("Failed to open directory.");
Serial.println();
Serial.print("> ");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory.");
Serial.println();
Serial.print("> ");
return;
}
File file = root.openNextFile();
while (file) {
String type = file.isDirectory() ? "DIR" : "FILE";
Serial.printf("%-32s %4s %8d bytes\n", file.name(), type.c_str(), file.size());
file = root.openNextFile();
}
Serial.println();
Serial.print("> ");
}
void changeDirectory(const char* dirName) {
if (dirName == NULL) {
Serial.println("Directory name not provided.");
Serial.println();
Serial.print("> ");
return;
}
if (strcmp(dirName, "..") == 0) {
int lastSlash = currentDir.lastIndexOf('/');
if (lastSlash != -1) {
currentDir = currentDir.substring(0, lastSlash);
if (currentDir.length() == 0) {
currentDir = "/";
}
}
} else {
if (!currentDir.endsWith("/")) {
currentDir += "/";
}
currentDir += dirName;
}
Serial.println();
Serial.print("> ");
}
void showFileContents(const char* filename) {
String filePath = filename;
if (currentDir != "/") {
filePath = currentDir + "/" + filename;
}
File file = SPIFFS.open(filePath, FILE_READ);
if (!file) {
Serial.println("File not found.");
Serial.println();
Serial.print("> ");
return;
}
while (file.available()) {
Serial.write(file.read());
}
file.close();
Serial.println();
Serial.print("> ");
}
void createFile(const char* filename) {
if (filename == NULL) {
Serial.println("File name not provided.");
Serial.println();
Serial.print("> ");
return;
}
String filePath = filename;
if (!filePath.startsWith("/")) {
filePath = currentDir + "/" + filePath;
}
File file = SPIFFS.open(filePath, FILE_WRITE);
if (!file) {
Serial.println("Failed to create file.");
Serial.println();
Serial.print("> ");
return;
}
file.close();
Serial.println("File created.");
Serial.println();
Serial.print("> ");
}
void createDirectory(const char* dirName) {
if (dirName == NULL) {
Serial.println("Directory name not provided.");
Serial.println();
Serial.print("> ");
return;
}
String dirPath = dirName;
if (!dirPath.startsWith("/")) {
dirPath = currentDir + "/" + dirPath;
}
if (SPIFFS.mkdir(dirPath)) {
Serial.println("Directory created.");
} else {
Serial.println("Failed to create directory.");
}
Serial.println();
Serial.print("> ");
}
void deleteFileOrDirectory(const char* name) {
if (name == NULL) {
Serial.println("Name not provided.");
Serial.println();
Serial.print("> ");
return;
}
String path = name;
if (currentDir != "/") {
path = currentDir + "/" + name;
}
if (SPIFFS.remove(path)) {
Serial.println("File/directory deleted.");
} else {
Serial.println("Failed to delete file/directory.");
}
Serial.println();
Serial.print("> ");
}
void renameFile(const char* oldName, const char* newName) {
if (oldName == NULL || newName == NULL) {
Serial.println("Old name or new name not provided.");
Serial.println();
Serial.print("> ");
return;
}
String oldPath = oldName;
String newPath = newName;
if (currentDir != "/") {
oldPath = currentDir + "/" + oldName;
newPath = currentDir + "/" + newName;
}
if (SPIFFS.rename(oldPath, newPath)) {
Serial.println("File renamed.");
} else {
Serial.println("Failed to rename file.");
}
Serial.println();
Serial.print("> ");
}
void moveFile(const char* src, const char* dest) {
String srcPath = src;
String destPath = dest;
if (currentDir != "/") {
srcPath = currentDir + "/" + src;
destPath = currentDir + "/" + dest;
}
if (SPIFFS.rename(srcPath, destPath)) {
Serial.println("File moved.");
} else {
Serial.println("Failed to move file.");
}
Serial.println();
Serial.print("> ");
}
void displayHelp() {
Serial.println("Available commands:");
for (auto& command : commands) {
Serial.printf("%s - %s\n", command.name, command.help);
}
Serial.println();
Serial.print("> ");
}
void pingCommand(const char* address, int count) {
if (address == NULL) {
Serial.println("Address not provided.");
Serial.println();
Serial.print("> ");
return;
}
if (count <= 0) {
count = 5;
}
Serial.printf("Pinging %s with %d packets:\n", address, count);
for (int i = 0; i < count; i++) {
if (Ping.ping(address)) {
Serial.printf("Ping %d successful\n", i + 1);
} else {
Serial.printf("Ping %d failed\n", i + 1);
}
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
Serial.println();
Serial.print("> ");
}
void ifconfigCommand() {
Serial.printf("IP Address: %s\n", WiFi.localIP().toString().c_str());
Serial.printf("Subnet Mask: %s\n", WiFi.subnetMask().toString().c_str());
Serial.printf("Gateway: %s\n", WiFi.gatewayIP().toString().c_str());
Serial.printf("DNS: %s\n", WiFi.dnsIP().toString().c_str());
Serial.printf("MAC Address: %s\n", WiFi.macAddress().c_str());
Serial.println();
Serial.print("> ");
}
void memoryInfoCommand() {
Serial.printf("Free Heap: %d bytes\n", ESP.getFreeHeap());
Serial.println();
Serial.print("> ");
}
void fetchmeCommand() {
const char* logo[] = {
" ___ _ _ ___ ___ ",
" / __|_ __ __ _ _ _| |_| |___ / _ \\/ __|",
" \\__ \\ '_ \\/ _` | '_| / / / -_) (_) \\__ \\",
" |___/ .__/\\__,_|_| |_\\_\\_\\___|\\___/|___/",
" |_| ",
" ",
" ESP32 build Alpha 0.1.0-r1 ",
" By angeldev0 "
};
int64_t uptimeSeconds = esp_timer_get_time() / 1000000;
int days = uptimeSeconds / 86400;
int hours = (uptimeSeconds % 86400) / 3600;
int minutes = (uptimeSeconds % 3600) / 60;
int seconds = uptimeSeconds % 60;
const char* info[] = {
"CPU: %s",
"Number of CPU cores: %d",
"SDK Version: %s",
"Free Heap: %d bytes",
"CPU Frequency: %d MHz",
"IP Address: %s",
"MAC Address: %s",
"Uptime: %02d/%02d/%02d/%02d (dd/hh/mm/ss)",
"Flash Chip Size: %d bytes",
"Sketch Size: %d bytes",
"Free Sketch Space: %d bytes",
"Chip Revision: %d",
"Temperature: %.2f °C",
"Voltage: %.2f V"
};
const char* cpuModel = ESP.getChipModel();
int cores = ESP.getChipCores();
const char* sdkVersion = ESP.getSdkVersion();
int freeHeap = ESP.getFreeHeap();
int cpuFreqMHz = ESP.getCpuFreqMHz();
String ipAddress = WiFi.localIP().toString();
String macAddress = WiFi.macAddress();
int flashChipSize = ESP.getFlashChipSize();
int sketchSize = ESP.getSketchSize();
int freeSketchSpace = ESP.getFreeSketchSpace();
int chipRevision = ESP.getChipRevision();
float temperature = 0.0;
float voltage = 0.0;
String formattedInfo[] = {
String(cpuModel),
String(cores),
String(sdkVersion),
String(freeHeap),
String(cpuFreqMHz),
ipAddress,
macAddress,
String(days) + "/" + String(hours) + "/" + String(minutes) + "/" + String(seconds),
String(flashChipSize),
String(sketchSize),
String(freeSketchSpace),
String(chipRevision),
String(temperature, 2),
String(voltage, 2)
};
int logoHeight = sizeof(logo) / sizeof(logo[0]);
int infoHeight = sizeof(info) / sizeof(info[0]);
int maxHeight = max(logoHeight, infoHeight);
for (int i = 0; i < maxHeight; ++i) {
if (i < logoHeight) {
Serial.print(logo[i]);
} else {
Serial.print(" ");
}
Serial.print(" | ");
if (i < infoHeight) {
Serial.println(formattedInfo[i]);
} else {
Serial.println();
}
}
Serial.println();
Serial.print("> ");
}
void rebootCommand() {
Serial.println("Rebooting...");
ESP.restart();
}
void uptimeCommand() {
Serial.printf("Uptime: %lld seconds\n", esp_timer_get_time() / 1000000);
Serial.println();
Serial.print("> ");
}
void freeMemCommand() {
Serial.printf("Free Heap: %d bytes\n", ESP.getFreeHeap());
Serial.println();
Serial.print("> ");
}
void handleCommand(char* input) {
if (strlen(input) == 0) return;
addToHistory(input);
char* arg1 = strchr(input, ' ');
if (arg1 != NULL) {
*arg1 = '\0';
arg1++;
}
char* arg2 = NULL;
if (arg1 != NULL) {
arg2 = strchr(arg1, ' ');
if (arg2 != NULL) {
*arg2 = '\0';
arg2++;
}
}
for (auto& command : commands) {
if (strcmp(input, command.name) == 0) {
command.func(arg1, arg2);
return;
}
}
Serial.println("Command not found. Type 'help' to see available commands.");
Serial.print("> ");
}
void addToHistory(const char* command) {
if (historyCount < MAX_HISTORY_LEN) {
strncpy(commandHistory[historyCount], command, MAX_COMMAND_LEN - 1);
commandHistory[historyCount][MAX_COMMAND_LEN - 1] = '\0';
historyCount++;
} else {
for (int i = 1; i < MAX_HISTORY_LEN; i++) {
strncpy(commandHistory[i - 1], commandHistory[i], MAX_COMMAND_LEN - 1);
commandHistory[i - 1][MAX_COMMAND_LEN - 1] = '\0';
}
strncpy(commandHistory[MAX_HISTORY_LEN - 1], command, MAX_COMMAND_LEN - 1);
commandHistory[MAX_HISTORY_LEN - 1][MAX_COMMAND_LEN - 1] = '\0';
}
historyIndex = historyCount;
}
void showCommandHistory() {
Serial.println("Command History:");
for (int i = 0; i < historyCount; i++) {
Serial.printf("%d: %s\n", i + 1, commandHistory[i]);
}
Serial.print("> ");
}
void completeCommand(char* input) {
int len = strlen(input);
for (auto& command : commands) {
if (strncmp(input, command.name, len) == 0) {
strcpy(input, command.name);
Serial.print("\r> ");
Serial.print(input);
return;
}
}
}
void handleHelpFlag(const char* command) {
if (command != NULL && strcmp(command, "--help") == 0) {
displayHelp();
}
}