diff --git a/include/global.h b/include/global.h index 64cf9ae..feef71f 100644 --- a/include/global.h +++ b/include/global.h @@ -6,6 +6,8 @@ extern String selectedNode; extern int selectedItem; extern int selectedLXC; extern int selectedVM; +extern String selectedDisk; +extern String selectedPool; // TODO remove later #endif \ No newline at end of file diff --git a/include/json/retrieve.h b/include/json/retrieve.h index db4ad3e..d25a8df 100644 --- a/include/json/retrieve.h +++ b/include/json/retrieve.h @@ -4,7 +4,7 @@ typedef struct { String name; - int cpu; + float cpu; int threads; String onlineStatus; long long mem; @@ -34,9 +34,29 @@ typedef struct { long long netout; } VM; + +typedef struct { + String devpath; + long long size; + String used; + String serial; + String model; + String vendor; + String health; +} Disk; + +typedef struct { + String name; + long long free; + long long size; + String health; +} Pool; + Node *getNodeInfo(int *numNodes); Container *getContainerInfo(int *numContainers, String node); VM *getVMInfo(int *numVMs, String node); +Disk *getDiskInfo(int *numDisks, String node); +Pool *getPoolInfo(int *numPools, String node); #endif /* JSON_RETRIEVE_H */ diff --git a/include/json/send.h b/include/json/send.h index 3945644..1dea592 100644 --- a/include/json/send.h +++ b/include/json/send.h @@ -3,6 +3,10 @@ #include void restartVM(String node, int vmid); void restartContainer(String node, int containerid); -void restartNode(String node); +void startVM(String node, int vmid); +void startContainer(String node, int containerid); +void stopVM(String node, int vmid); +void stopContainer(String node, int containerid); + #endif /* JSON_SEND_H */ diff --git a/include/json/utils.h b/include/json/utils.h index a88712f..8d3e0a7 100644 --- a/include/json/utils.h +++ b/include/json/utils.h @@ -6,5 +6,7 @@ Node getNode(String name); Container getContainer(int id, String node); VM getVM(int id, String node); +Disk getDisk(String devpath, String node); +Pool getPool(String name, String node); #endif /* JSON_UTILS_H */ diff --git a/include/manage.h b/include/manage.h index 8be4185..0d744c2 100644 --- a/include/manage.h +++ b/include/manage.h @@ -1,5 +1,11 @@ #ifndef MANAGE_H #define MANAGE_H +void vmRestart(); +void containerRestart(); +void vmStart(); +void containerStart(); +void vmStop(); +void containerStop(); #endif /* MANAGE_H */ diff --git a/include/menu.h b/include/menu.h index dcd013b..42c243d 100644 --- a/include/menu.h +++ b/include/menu.h @@ -12,8 +12,13 @@ typedef struct { void listNodes(Node* nodes, int numItems); void listContainers(Container* containers, int numItems); void listVMs(VM* vms, int numItems); +void listDisks(Disk* disks, int numItems); +void listPools(Pool* pools, int numItems); void mainMenu(); +void manageContainerMenu(); +void manageVMMenu(); extern int selectedItem; +extern int selectedPage; #endif \ No newline at end of file diff --git a/include/pin.h b/include/pin.h new file mode 100644 index 0000000..b945173 --- /dev/null +++ b/include/pin.h @@ -0,0 +1,14 @@ +#ifndef PIN_H +#define PIN_H +#include +const String LOCK_PIN = ""; +/** + * 0 = A Button + * 1 = B Button + * 2 = Down + * 3 = Up + * 4 = Right + * 5 = Left +*/ + +#endif /* PIN_H */ diff --git a/include/statistics.h b/include/statistics.h index 955b86c..a4f60f7 100644 --- a/include/statistics.h +++ b/include/statistics.h @@ -3,5 +3,7 @@ void nodeInfo(); void containerInfo(); void vmInfo(); +void diskInfo(); +void poolInfo(); #endif /* STATISTICS_H */ diff --git a/include/utils.h b/include/utils.h index f62fa07..a418f4c 100644 --- a/include/utils.h +++ b/include/utils.h @@ -4,5 +4,7 @@ void displayError(String message); void connectWiFi(); +bool enterPin(); +int pinListener(); #endif /* UTILS_H */ diff --git a/src/json/retrieve.cpp b/src/json/retrieve.cpp index 38cef4e..8f85fbf 100644 --- a/src/json/retrieve.cpp +++ b/src/json/retrieve.cpp @@ -19,7 +19,7 @@ Node *getNodeInfo(int *numNodes) if (httpCode > 0) { String json = http.getString(); - DynamicJsonDocument doc(6144); + DynamicJsonDocument doc(8096); deserializeJson(doc, json); JsonArray nodes = doc["data"].as(); @@ -28,7 +28,7 @@ Node *getNodeInfo(int *numNodes) for (int i = 0; i < nodes.size(); i++) { nodeArray[i].name = nodes[i]["node"].as(); - nodeArray[i].cpu = nodes[i]["cpu"].as(); + nodeArray[i].cpu = nodes[i]["cpu"].as(); nodeArray[i].threads = nodes[i]["maxcpu"].as(); nodeArray[i].onlineStatus = nodes[i]["status"].as(); nodeArray[i].mem = nodes[i]["mem"].as(); @@ -58,7 +58,7 @@ Container *getContainerInfo(int *numContainers, String node) if (httpCode > 0) { String json = http.getString(); - DynamicJsonDocument doc(1024); + DynamicJsonDocument doc(8096); deserializeJson(doc, json); JsonArray containers = doc["data"].as(); Container *containerArray = new Container[containers.size()]; @@ -94,7 +94,7 @@ VM *getVMInfo(int *numVMs, String node) if (httpCode > 0) { String json = http.getString(); - DynamicJsonDocument doc(1024); + DynamicJsonDocument doc(8096); deserializeJson(doc, json); JsonArray vms = doc["data"].as(); VM *vmArray = new VM[vms.size()]; @@ -115,4 +115,74 @@ VM *getVMInfo(int *numVMs, String node) return vmArray; } throw std::runtime_error("Can't get VM info: HTTP request failed with code: " + httpCode); +} + +Disk *getDiskInfo(int *numDisks, String node) +{ + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/disks/list"; + String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; + char authc[auth.length() + 1]; + auth.toCharArray(authc, auth.length() + 1); + http.begin(apiAddress); + http.setAuthorization(authc); + int httpCode = http.GET(); + + if (httpCode > 0) + { + String json = http.getString(); + DynamicJsonDocument doc(32768); + deserializeJson(doc, json); + JsonArray disks = doc["data"].as(); + Disk *diskArray = new Disk[disks.size()]; + + for (int i = 0; i < disks.size(); i++) + { + Serial.println(disks[i]["devpath"].as()); + diskArray[i].devpath = disks[i]["devpath"].as(); + diskArray[i].size = disks[i]["size"].as(); + diskArray[i].used = disks[i]["used"].as(); + diskArray[i].serial = disks[i]["serial"].as(); + diskArray[i].model = disks[i]["model"].as(); + diskArray[i].vendor = disks[i]["vendor"].as(); + diskArray[i].health = disks[i]["health"].as(); + } + + *numDisks = disks.size(); + return diskArray; + } + throw std::runtime_error("Can't get disk info: HTTP request failed with code: " + httpCode); +} + +Pool *getPoolInfo(int *numPools, String node) +{ + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/disks/zfs"; + String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; + char authc[auth.length() + 1]; + auth.toCharArray(authc, auth.length() + 1); + http.begin(apiAddress); + http.setAuthorization(authc); + int httpCode = http.GET(); + + if (httpCode > 0) + { + String json = http.getString(); + DynamicJsonDocument doc(32768); + deserializeJson(doc, json); + JsonArray pools = doc["data"].as(); + Pool *poolArray = new Pool[pools.size()]; + + for (int i = 0; i < pools.size(); i++) + { + poolArray[i].name = pools[i]["name"].as(); + poolArray[i].free = pools[i]["free"].as(); + poolArray[i].size = pools[i]["size"].as(); + poolArray[i].health = pools[i]["health"].as(); + } + + *numPools = pools.size(); + return poolArray; + } + throw std::runtime_error("Can't get pool info: HTTP request failed with code: " + httpCode); } \ No newline at end of file diff --git a/src/json/send.cpp b/src/json/send.cpp index bb7ef22..936d8c3 100644 --- a/src/json/send.cpp +++ b/src/json/send.cpp @@ -39,10 +39,10 @@ void restartContainer(String node, int containerid) } } -void restartNode(String node) +void startVM(String node, int vmid) { HTTPClient http; - String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/status/reboot"; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/start"; String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; char authc[auth.length() + 1]; auth.toCharArray(authc, auth.length() + 1); @@ -52,7 +52,57 @@ void restartNode(String node) http.end(); if(httpCode == 0) { - throw std::runtime_error("Can't restart container. Error code: " + httpCode); + throw std::runtime_error("Can't start VM. Error code: " + httpCode); } } +void startContainer(String node, int containerid) +{ + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/start"; + String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; + char authc[auth.length() + 1]; + auth.toCharArray(authc, auth.length() + 1); + http.begin(apiAddress); + http.setAuthorization(authc); + int httpCode = http.POST(""); + http.end(); + + if(httpCode == 0) { + throw std::runtime_error("Can't start container. Error code: " + httpCode); + } +} + +void stopVM(String node, int vmid) +{ + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu/" + vmid + "/status/stop"; + String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; + char authc[auth.length() + 1]; + auth.toCharArray(authc, auth.length() + 1); + http.begin(apiAddress); + http.setAuthorization(authc); + int httpCode = http.POST(""); + http.end(); + + if(httpCode == 0) { + throw std::runtime_error("Can't stop VM. Error code: " + httpCode); + } +} + +void stopContainer(String node, int containerid) +{ + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc/" + containerid + "/status/stop"; + String auth = "PVEAPIToken=" + PROXMOX_TOKEN_USER + "!" + PROXMOX_TOKEN_NAME + "=" + PROXMOX_TOKEN_SECRET; + char authc[auth.length() + 1]; + auth.toCharArray(authc, auth.length() + 1); + http.begin(apiAddress); + http.setAuthorization(authc); + int httpCode = http.POST(""); + http.end(); + + if(httpCode == 0) { + throw std::runtime_error("Can't stop container. Error code: " + httpCode); + } +} \ No newline at end of file diff --git a/src/json/utils.cpp b/src/json/utils.cpp index 661e8b3..24310cd 100644 --- a/src/json/utils.cpp +++ b/src/json/utils.cpp @@ -50,3 +50,35 @@ VM getVM(int id, String node) throw std::runtime_error("Can't find the requested vm in the array"); } + +Disk getDisk(String devpath, String node) +{ + int numDisks; + + Disk *disks = getDiskInfo(&numDisks, node); + for (int i = 0; i < numDisks; i++) + { + if (disks[i].devpath == devpath) + { + return disks[i]; + } + } + + throw std::runtime_error("Can't find the requested disk in the array"); +} + +Pool getPool(String name, String node) +{ + int numPools; + + Pool *pools = getPoolInfo(&numPools, node); + for (int i = 0; i < numPools; i++) + { + if (pools[i].name == name) + { + return pools[i]; + } + } + + throw std::runtime_error("Can't find the requested pool in the array"); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index e2cb79d..05fcc84 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,16 +7,9 @@ #include #include -void setup() -{ - Serial.begin(115200); - GO.begin(); - connectWiFi(); -} void loop() { - if (WiFi.status() != WL_CONNECTED) { displayError("WiFi Connection Lost"); @@ -28,7 +21,9 @@ void loop() int numNodes; Node *nodes = getNodeInfo(&numNodes); listNodes(nodes, numNodes); + delete[] nodes; selectedItem = 0; + selectedPage = 0; mainMenu(); } catch (const std::exception &e) @@ -36,5 +31,18 @@ void loop() Serial.println(e.what()); displayError(e.what()); } +} + +void setup() +{ + Serial.begin(115200); + GO.begin(); + GO.lcd.setTextWrap(false); + bool pinCorrect = false; + while (!pinCorrect) { + pinCorrect = enterPin(); + } + connectWiFi(); + Serial.println("done setup"); +} -} \ No newline at end of file diff --git a/src/manage.cpp b/src/manage.cpp index 0e1ce99..5ed0af6 100644 --- a/src/manage.cpp +++ b/src/manage.cpp @@ -6,22 +6,52 @@ #include #include -void nodeRestart() +void vmRestart() { - Serial.println("node restart"); + Serial.println("vm restart"); selectedItem = 0; + int numVMs; + VM *vms = getVMInfo(&numVMs, selectedNode); + if (vms != NULL) + { + listVMs(vms, numVMs); + delete[] vms; + restartVM(selectedNode, selectedVM); - restartNode(selectedNode); + GO.lcd.clearDisplay(); + GO.lcd.setCursor(0, 0); + GO.lcd.println("done"); + + delay(2000); + manageVMMenu(); + } +} + +void containerRestart() +{ + Serial.println("lxc restart"); + selectedItem = 0; + int numContainers; + Container *containers = getContainerInfo(&numContainers, selectedNode); + if (containers != NULL) + { + listContainers(containers, numContainers); + delete[] containers; - GO.lcd.clearDisplay(); - GO.lcd.println("done"); + restartContainer(selectedNode, selectedLXC); + GO.lcd.clearDisplay(); + GO.lcd.setCursor(0, 0); + GO.lcd.println("done"); - delay(2000); + delay(2000); + manageContainerMenu(); + } } -void vmRestart() + +void vmStart() { - Serial.println("vm restart"); + Serial.println("vm start"); selectedItem = 0; int numVMs; VM *vms = getVMInfo(&numVMs, selectedNode); @@ -29,7 +59,7 @@ void vmRestart() { listVMs(vms, numVMs); - restartVM(selectedNode, selectedVM); + startVM(selectedNode, selectedVM); GO.lcd.clearDisplay(); GO.lcd.println("done"); @@ -38,9 +68,9 @@ void vmRestart() } } -void containerRestart() +void containerStart() { - Serial.println("lxc restart"); + Serial.println("lxc start"); selectedItem = 0; int numContainers; Container *containers = getContainerInfo(&numContainers, selectedNode); @@ -48,7 +78,26 @@ void containerRestart() { listContainers(containers, numContainers); - restartContainer(selectedNode, selectedLXC); + startContainer(selectedNode, selectedLXC); + GO.lcd.clearDisplay(); + GO.lcd.println("done"); + + delay(2000); + } +} + +void vmStop() +{ + Serial.println("vm stop"); + selectedItem = 0; + int numVMs; + VM *vms = getVMInfo(&numVMs, selectedNode); + if (vms != NULL) + { + listVMs(vms, numVMs); + + stopVM(selectedNode, selectedVM); + GO.lcd.clearDisplay(); GO.lcd.println("done"); @@ -56,104 +105,20 @@ void containerRestart() } } +void containerStop() +{ + Serial.println("lxc stop"); + selectedItem = 0; + int numContainers; + Container *containers = getContainerInfo(&numContainers, selectedNode); + if (containers != NULL) + { + listContainers(containers, numContainers); + + stopContainer(selectedNode, selectedLXC); + GO.lcd.clearDisplay(); + GO.lcd.println("done"); -// void nodeStart() -// { -// Serial.println("node start"); -// selectedItem = 0; - -// startNode(selectedNode); - -// GO.lcd.clearDisplay(); -// GO.lcd.println("done"); - -// delay(2000); -// } - -// void vmStart() -// { -// Serial.println("vm start"); -// selectedItem = 0; -// int numVMs; -// VM *vms = getVMInfo(&numVMs, selectedNode); -// if (vms != NULL) -// { -// listVMs(vms, numVMs); - -// startVM(selectedNode, selectedVM); - -// GO.lcd.clearDisplay(); -// GO.lcd.println("done"); - -// delay(2000); -// } -// } - -// void containerStart() -// { -// Serial.println("lxc start"); -// selectedItem = 0; -// int numContainers; -// Container *containers = getContainerInfo(&numContainers, selectedNode); -// if (containers != NULL) -// { -// listContainers(containers, numContainers); - -// startContainer(selectedNode, selectedLXC); -// GO.lcd.clearDisplay(); -// GO.lcd.println("done"); - -// delay(2000); -// } -// } - - -// void nodeStop() -// { -// Serial.println("node stop"); -// selectedItem = 0; - -// stopNode(selectedNode); - -// GO.lcd.clearDisplay(); -// GO.lcd.println("done"); - -// delay(2000); -// } - -// void vmStop() -// { -// Serial.println("vm stop"); -// selectedItem = 0; -// int numVMs; -// VM *vms = getVMInfo(&numVMs, selectedNode); -// if (vms != NULL) -// { -// listVMs(vms, numVMs); - -// stopVM(selectedNode, selectedVM); - -// GO.lcd.clearDisplay(); -// GO.lcd.println("done"); - -// delay(2000); -// } -// } - -// void containerStop() -// { -// Serial.println("lxc stop"); -// selectedItem = 0; -// int numContainers; -// Container *containers = getContainerInfo(&numContainers, selectedNode); -// if (containers != NULL) -// { -// listContainers(containers, numContainers); - -// stopContainer(selectedNode, selectedLXC); -// GO.lcd.clearDisplay(); -// GO.lcd.println("done"); - -// delay(2000); -// } -// } \ No newline at end of file + delay(2000); + } +} \ No newline at end of file diff --git a/src/menu.cpp b/src/menu.cpp index dc73dfc..5e1eaf2 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -4,167 +4,304 @@ #include #include #include +#include const int MAIN_TEXT_COLOR = WHITE; const int MAIN_TEXT_SIZE = 2; - +const int ITEMS_PER_PAGE = 12; int selectedItem = 0; +int selectedPage = 0; String selectedNode = ""; int selectedLXC = 0; int selectedVM = 0; - - - - +String selectedDisk = ""; +String selectedPool = ""; // Array of the main menu items MenuItem mainMenuItems[] = { - {"Node Information", &nodeInfo}, - {"Container Information", &containerInfo}, - {"VM Information", &vmInfo} + {"Node Information", &nodeInfo}, + {"Container Information", &containerInfo}, + {"VM Information", &vmInfo}, + {"Disk Information", &diskInfo}, + {"ZFS Pool Information", &poolInfo}, + {"Manage VM", &manageVMMenu}, + {"Manage Container", &manageContainerMenu}}; + + +MenuItem manageVMItems[] = { + {"Restart", &vmRestart}, + {"Start", &vmStart}, + {"Stop", &vmStop}, }; +MenuItem manageContainerItems[] = { + {"Restart", &containerRestart}, + {"Start", &containerStart}, + {"Stop", &containerStop}, +}; -int buttonListener(int numItems) { - delay(200); - while (true) { +int buttonListener(int numItems) +{ + delay(300); + while (true) + { GO.update(); - if (GO.JOY_Y.isAxisPressed() == 1 && selectedItem < (numItems - 1)) { + if (GO.JOY_Y.isAxisPressed() == 1 && selectedItem < (numItems - 1)) + { selectedItem++; Serial.println(selectedItem); break; } - if (GO.JOY_Y.isAxisPressed() == 2 && selectedItem > 0) { + if (GO.JOY_Y.isAxisPressed() == 2 && selectedItem > 0) + { selectedItem--; Serial.println(selectedItem); break; } - if (GO.BtnA.isPressed() == 1) { - delay(300); + if (GO.JOY_X.isAxisPressed() == 1 && selectedPage + 1 < (numItems / ITEMS_PER_PAGE)) + { + selectedPage++; + selectedItem = selectedPage * ITEMS_PER_PAGE; + Serial.println(selectedPage); + break; + } + if (GO.JOY_X.isAxisPressed() == 2 && selectedPage > 0) + { + selectedPage--; + selectedItem = selectedPage * ITEMS_PER_PAGE; + Serial.println(selectedPage); + break; + } + if (GO.BtnA.isPressed() == 1) + { + delay(200); return 1; } - if (GO.BtnB.isPressed() == 1) { - delay(300); + if (GO.BtnB.isPressed() == 1) + { + delay(200); return 2; } - + delay(50); } return 0; } -void drawMenu(MenuItem menuItems[], int numItems) { +void drawMenu(MenuItem menuItems[], int numItems, String menuTitle) +{ GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor(MAIN_TEXT_COLOR); GO.lcd.setTextSize(MAIN_TEXT_SIZE); - + GO.lcd.println(menuTitle); + GO.lcd.println("--------------------------"); - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { + for (int i = 0; i < numItems; i++) + { + if (selectedItem == i) + { GO.lcd.print("> "); } GO.lcd.println(menuItems[i].name); } - switch (buttonListener(numItems)) { - case 1: - Serial.println("selected " + selectedItem); - menuItems[selectedItem].function(); - break; - case 2: - Serial.println("back"); - break; - default: - drawMenu(menuItems, numItems); - break; + switch (buttonListener(numItems)) + { + case 1: + Serial.println("selected " + selectedItem); + menuItems[selectedItem].function(); + break; + case 2: + Serial.println("back"); + break; + default: + drawMenu(menuItems, numItems, menuTitle); + break; } +} +void mainMenu() +{ + int numItems = sizeof(mainMenuItems) / sizeof(MenuItem); + drawMenu(mainMenuItems, numItems, "Main Menu"); } -void mainMenu(){ - int numItems = sizeof(mainMenuItems) / sizeof(MenuItem); - drawMenu(mainMenuItems, numItems); + +void manageVMMenu() +{ + selectedItem = 0; + int numItems = sizeof(manageVMItems) / sizeof(MenuItem); + drawMenu(manageVMItems, numItems, "Manage VM"); + mainMenu(); } -void listNodes(Node* nodes, int numItems) { +void manageContainerMenu() +{ + selectedItem = 0; + int numItems = sizeof(manageContainerItems) / sizeof(MenuItem); + drawMenu(manageContainerItems, numItems, "Manage Container"); + mainMenu(); +} + +void listNodes(Node *nodes, int numItems) +{ GO.lcd.clearDisplay(); GO.lcd.setTextColor(MAIN_TEXT_COLOR); GO.lcd.setTextSize(MAIN_TEXT_SIZE); GO.lcd.setCursor(0, 0); + GO.lcd.println("Select Node (Page " + String(selectedPage + 1) + ")"); + GO.lcd.println("--------------------------"); - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { + for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) + { + Serial.println("running loop"); + if (selectedItem == i) + { GO.lcd.print("> "); } GO.lcd.println(nodes[i].name); } - - switch (buttonListener(numItems)) { - case 1: - Serial.println("selected " + selectedItem); - selectedNode = nodes[selectedItem].name; - break; - case 2: - Serial.println("back"); - break; - default: - listNodes(nodes, numItems); - break; + Serial.println("completed loop"); + switch (buttonListener(numItems)) + { + case 1: + Serial.println("selected " + selectedItem); + selectedNode = nodes[selectedItem].name; + break; + case 2: + Serial.println("back"); + break; + default: + listNodes(nodes, numItems); + break; } } -void listContainers(Container* containers, int numItems) { +void listContainers(Container *containers, int numItems) +{ GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor(MAIN_TEXT_COLOR); GO.lcd.setTextSize(MAIN_TEXT_SIZE); + GO.lcd.println("Select Container (Page " + String(selectedPage + 1) + ")"); + GO.lcd.println("--------------------------"); - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { + for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) + { + if (selectedItem == i) + { GO.lcd.print("> "); } GO.lcd.println(String(containers[i].id) + ": " + containers[i].name); } - switch (buttonListener(numItems)) { - case 1: - selectedLXC = containers[selectedItem].id; - break; - case 2: - Serial.println("back"); - break; - default: - listContainers(containers, numItems); - break; + switch (buttonListener(numItems)) + { + case 1: + selectedLXC = containers[selectedItem].id; + break; + case 2: + Serial.println("back"); + break; + default: + listContainers(containers, numItems); + break; } - } - -void listVMs(VM* vms, int numItems) { +void listVMs(VM *vms, int numItems) +{ GO.lcd.clearDisplay(); GO.lcd.setCursor(0, 0); GO.lcd.setTextColor(MAIN_TEXT_COLOR); GO.lcd.setTextSize(MAIN_TEXT_SIZE); + GO.lcd.println("Select VM (Page " + String(selectedPage + 1) + ")"); + GO.lcd.println("--------------------------"); - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { + for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) + { + if (selectedItem == i) + { GO.lcd.print("> "); } GO.lcd.println(String(vms[i].id) + ": " + vms[i].name); } - switch (buttonListener(numItems)) { - case 1: - selectedVM = vms[selectedItem].id; - break; - case 2: - Serial.println("back"); - break; - default: - listVMs(vms, numItems); - break; + switch (buttonListener(numItems)) + { + case 1: + selectedVM = vms[selectedItem].id; + break; + case 2: + Serial.println("back"); + break; + default: + listVMs(vms, numItems); + break; } +} + +void listDisks(Disk *disks, int numItems) +{ + GO.lcd.clearDisplay(); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(MAIN_TEXT_COLOR); + GO.lcd.setTextSize(MAIN_TEXT_SIZE); + GO.lcd.println("Select Disk (Page " + String(selectedPage + 1) + ")"); + GO.lcd.println("--------------------------"); + for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) + { + if (selectedItem == i) + { + GO.lcd.print("> "); + } + GO.lcd.println(disks[i].devpath); + } + + switch (buttonListener(numItems)) + { + case 1: + selectedDisk = disks[selectedItem].devpath; + break; + case 2: + Serial.println("back"); + break; + default: + listDisks(disks, numItems); + break; + } } + +void listPools(Pool *pools, int numItems) +{ + GO.lcd.clearDisplay(); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(MAIN_TEXT_COLOR); + GO.lcd.setTextSize(MAIN_TEXT_SIZE); + GO.lcd.println("Select Pool (Page " + String(selectedPage + 1) + ")"); + GO.lcd.println("--------------------------"); + + for (int i = selectedPage * ITEMS_PER_PAGE; i < numItems && i < (selectedPage + 1) * ITEMS_PER_PAGE; i++) + { + if (selectedItem == i) + { + GO.lcd.print("> "); + } + GO.lcd.println(pools[i].name); + } + + switch (buttonListener(numItems)) + { + case 1: + selectedPool = pools[selectedItem].name; + break; + case 2: + Serial.println("back"); + break; + default: + listPools(pools, numItems); + break; + } +} \ No newline at end of file diff --git a/src/statistics.cpp b/src/statistics.cpp index 98dec1b..64ef645 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -5,6 +5,10 @@ #include #include +const int BACKGROUND_COLOR = WHITE; +const int TEXT_COLOR = BLACK; +const int TEXT_SIZE = 2; + String convertBytes(long long value) { if (value > 1099511627776) { return String(value / 1099511627776) + " TB"; @@ -34,17 +38,17 @@ String convertTime(long long value) { void printNodeStats(Node node) { - GO.lcd.fillScreen(WHITE); + GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.setCursor(0, 0); - GO.lcd.setTextColor(BLACK); + GO.lcd.setTextColor(TEXT_COLOR); - GO.lcd.setTextSize(3); + GO.lcd.setTextSize(TEXT_SIZE); GO.lcd.println(node.name); - GO.lcd.setTextSize(2); + GO.lcd.println("--------------------------"); GO.lcd.println("Status: " + node.onlineStatus); GO.lcd.println("Uptime: " + convertTime(node.uptime)); - GO.lcd.println("CPU: " + String(node.cpu) + "%"); + GO.lcd.println("CPU: " + String(node.cpu * 100) + "%"); GO.lcd.println("Threads: " + String(node.threads)); GO.lcd.println("RAM: " + convertBytes(node.mem)); GO.lcd.println("Max RAM: " + convertBytes(node.maxmem)); @@ -55,13 +59,12 @@ void printNodeStats(Node node) void printContainerStats(Container container) { - GO.lcd.fillScreen(WHITE); + GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.setCursor(0, 0); - GO.lcd.setTextColor(BLACK); + GO.lcd.setTextColor(TEXT_COLOR); - GO.lcd.setTextSize(3); + GO.lcd.setTextSize(TEXT_SIZE); GO.lcd.println(String(container.id) + ": " + container.name); - GO.lcd.setTextSize(2); GO.lcd.println("--------------------------"); GO.lcd.println("Status: " + container.onlineStatus); GO.lcd.println("Uptime: " + convertTime(container.uptime)); @@ -72,13 +75,11 @@ void printContainerStats(Container container) void printVMStats(VM vm) { - GO.lcd.fillScreen(WHITE); + GO.lcd.fillScreen(BACKGROUND_COLOR); GO.lcd.setCursor(0, 0); - GO.lcd.setTextColor(BLACK); - - GO.lcd.setTextSize(3); + GO.lcd.setTextColor(TEXT_COLOR); + GO.lcd.setTextSize(TEXT_SIZE); GO.lcd.println(String(vm.id) + ": " + vm.name); - GO.lcd.setTextSize(2); GO.lcd.println("--------------------------"); GO.lcd.println("Status: " + vm.onlineStatus); GO.lcd.println("Uptime: " + convertTime(vm.uptime)); @@ -86,48 +87,161 @@ void printVMStats(VM vm) GO.lcd.println("Max Disk: " + convertBytes(vm.maxdisk)); } +void printDiskStats(Disk disk) +{ + + GO.lcd.fillScreen(BACKGROUND_COLOR); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(TEXT_COLOR); + GO.lcd.setTextSize(TEXT_SIZE); + + GO.lcd.println(disk.devpath); + GO.lcd.println("--------------------------"); + GO.lcd.println("Vendor: " + disk.vendor); + GO.lcd.println("Model: " + disk.model); + GO.lcd.println("Serial: " + disk.serial); + GO.lcd.println("Size: " + convertBytes(disk.size)); + GO.lcd.println("Used For: " + disk.used); + GO.lcd.println("Health: " + disk.health); +} + +void printPoolStats(Pool pool) +{ + + GO.lcd.fillScreen(BACKGROUND_COLOR); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(TEXT_COLOR); + GO.lcd.setTextSize(TEXT_SIZE); + + GO.lcd.println(pool.name); + GO.lcd.println("--------------------------"); + GO.lcd.println("Free: " + convertBytes(pool.free)); + GO.lcd.println("Size: " + convertBytes(pool.size)); + GO.lcd.println("Health: " + pool.health); +} + void nodeInfo() { Serial.println("nodeinfo"); + unsigned long lastUpdate = millis(); + int updateInterval = 3000; while (true) { + if(lastUpdate + updateInterval < millis()) { + printNodeStats(getNode(selectedNode)); + lastUpdate = millis(); + } - printNodeStats(getNode(selectedNode)); - delay(2000); + GO.update(); + if(GO.BtnB.isPressed()) { + break; + } } + mainMenu(); } void containerInfo() { Serial.println("container info"); selectedItem = 0; + selectedPage = 0; int numContainers; Container *containers = getContainerInfo(&numContainers, selectedNode); listContainers(containers, numContainers); + delete[] containers; + unsigned long lastUpdate = millis(); + int updateInterval = 3000; while (true) { - printContainerStats(getContainer(selectedLXC, selectedNode)); - delay(5000); + if(lastUpdate + updateInterval < millis()) { + printContainerStats(getContainer(selectedLXC, selectedNode)); + lastUpdate = millis(); + } + + GO.update(); + if(GO.BtnB.isPressed()) { + mainMenu(); + break; + } } + } void vmInfo() { Serial.println("vm info"); selectedItem = 0; + selectedPage = 0; int numVMs; VM *vms = getVMInfo(&numVMs, selectedNode); if (vms != NULL) { listVMs(vms, numVMs); - + delete[] vms; + unsigned long lastUpdate = millis(); + int updateInterval = 3000; while (true) { - printVMStats(getVM(selectedVM, selectedNode)); - delay(5000); + if(lastUpdate + updateInterval < millis()) { + printVMStats(getVM(selectedVM, selectedNode)); + lastUpdate = millis(); + } + GO.update(); + if(GO.BtnB.isPressed()) { + mainMenu(); + break; + } + } + } +} + +void diskInfo() +{ + Serial.println("disk info"); + selectedItem = 0; + selectedPage = 0; + int numDisks; + Disk *disks = getDiskInfo(&numDisks, selectedNode); + if (disks != NULL) + { + listDisks(disks, numDisks); + delete[] disks; + + printDiskStats(getDisk(selectedDisk, selectedNode)); + while (true) + { + GO.update(); + if(GO.BtnB.isPressed()) { + mainMenu(); + break; + } } } } + +void poolInfo() +{ + Serial.println("pool info"); + selectedItem = 0; + selectedPage = 0; + int numPools; + Pool *pools = getPoolInfo(&numPools, selectedNode); + if (pools != NULL) + { + listPools(pools, numPools); + delete[] pools; + + printPoolStats(getPool(selectedPool, selectedNode)); + while (true) + { + GO.update(); + if(GO.BtnB.isPressed()) { + mainMenu(); + break; + } + } + } +} \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp index c302fe3..efe226d 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,6 +1,7 @@ #include #include #include +#include /** Display an error on the screen */ @@ -15,12 +16,129 @@ void displayError(String message) { void connectWiFi() { WiFi.begin(WIFI_SSID, WIFI_PASS); + GO.lcd.clearDisplay(); + GO.lcd.setCursor(0, 0); GO.lcd.print("Connecting"); + while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); GO.lcd.print("."); } +} + + +int pinListener() +{ + delay(300); + while (true) + { + GO.update(); + if (GO.BtnA.isPressed() == 1) + { + return 0; + } + + if (GO.BtnB.isPressed() == 1) + { + return 1; + } + + if (GO.JOY_Y.isAxisPressed() == 1) + { + return 2; + } + + if (GO.JOY_Y.isAxisPressed() == 2) + { + return 3; + } + + if (GO.JOY_X.isAxisPressed() == 1) + { + return 4; + } + + if (GO.JOY_X.isAxisPressed() == 2) + { + return 5; + } + + if (GO.BtnStart.isPressed() == 1) + { + return 6; + } + + if (GO.BtnMenu.isPressed() == 1) + { + return 7; + } + delay(50); + } + return 7; +} + +bool enterPin() +{ + GO.lcd.clearDisplay(); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(WHITE); + GO.lcd.setTextSize(2); + GO.lcd.println("Enter pin"); + GO.lcd.println("--------------------------"); + GO.lcd.setTextSize(1); + GO.lcd.println("Start to Confirm | Menu to Reset"); + GO.lcd.setTextSize(2); + GO.lcd.println("--------------------------"); + bool done = false; + String pin = ""; + + while (!done) + { + if (pin != ""){ + GO.lcd.print("*"); + } + Serial.println(pin); + switch (pinListener()) + { + case 6: + done = true; + break; + case 0: + pin += "0"; + break; + case 1: + pin += "1"; + break; + case 2: + pin += "2"; + break; + case 3: + pin += "3"; + break; + case 4: + pin += "4"; + break; + case 5: + pin += "5"; + break; + default: + pin = ""; + done = true; + break; + } + } + + if (pin == LOCK_PIN) { + return true; + } + Serial.println("incorrect: " + pin); + + if (pin != "") { + displayError("Incorrect Pin"); + } + return false; + } \ No newline at end of file