diff --git a/include/global.h b/include/global.h new file mode 100644 index 0000000..12ebf70 --- /dev/null +++ b/include/global.h @@ -0,0 +1,9 @@ +#include +#ifndef GLOBAL_H_ +#define GLOBAL_H_ + +extern String selectedNode; +extern int selectedItem; + + +#endif \ No newline at end of file diff --git a/include/json/retrieve.h b/include/json/retrieve.h new file mode 100644 index 0000000..386f325 --- /dev/null +++ b/include/json/retrieve.h @@ -0,0 +1,9 @@ +#ifndef JSON_RETRIEVE_H +#define JSON_RETRIEVE_H +#include + +JsonArray getNodeInfo(); +JsonArray getContainerInfo(String node); +JsonArray getVMInfo(String node); + +#endif /* JSON_RETRIEVE_H */ diff --git a/include/json/utils.h b/include/json/utils.h new file mode 100644 index 0000000..6414eeb --- /dev/null +++ b/include/json/utils.h @@ -0,0 +1,8 @@ +#ifndef JSON_UTILS_H +#define JSON_UTILS_H +#include + +JsonObject getNode(String name, JsonArray nodes); +JsonObject getContainer(int id, JsonArray containers); + +#endif /* JSON_UTILS_H */ diff --git a/include/menu.h b/include/menu.h new file mode 100644 index 0000000..6d9381b --- /dev/null +++ b/include/menu.h @@ -0,0 +1,17 @@ +#ifndef MENU_H_ +#define MENU_H_ +#include +#include +// Struct for static menu items such as on the main menu. Has the name of the menu item and a function to run when it is selected. +typedef struct { + String name; + void (*function)(); +} MenuItem; + +void listNodes(JsonArray nodes); +int listContainers(JsonArray containers); +void mainMenu(); + +extern int selectedItem; + +#endif \ No newline at end of file diff --git a/include/server.hpp b/include/server.h similarity index 66% rename from include/server.hpp rename to include/server.h index 3944e07..6125df3 100644 --- a/include/server.hpp +++ b/include/server.h @@ -1,12 +1,14 @@ #include +#ifndef SERVER_H_ +#define SERVER_H_ /** * Enter WiFi network and Proxmox information */ -const char* WIFI_SSID = ""; -const char* WIFI_PASS = ""; const String PROXMOX_ADDRESS = ""; const String PROXMOX_TOKEN_USER = ""; const String PROXMOX_TOKEN_NAME = ""; -const String PROXMOX_TOKEN_SECRET = ""; \ No newline at end of file +const String PROXMOX_TOKEN_SECRET = ""; + +#endif \ No newline at end of file diff --git a/include/statistics.h b/include/statistics.h new file mode 100644 index 0000000..955b86c --- /dev/null +++ b/include/statistics.h @@ -0,0 +1,7 @@ +#ifndef STATISTICS_H +#define STATISTICS_H +void nodeInfo(); +void containerInfo(); +void vmInfo(); + +#endif /* STATISTICS_H */ diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..f62fa07 --- /dev/null +++ b/include/utils.h @@ -0,0 +1,8 @@ +#ifndef UTILS_H +#define UTILS_H +#include + +void displayError(String message); +void connectWiFi(); + +#endif /* UTILS_H */ diff --git a/include/wifi_info.h b/include/wifi_info.h new file mode 100644 index 0000000..d5951fc --- /dev/null +++ b/include/wifi_info.h @@ -0,0 +1,11 @@ +#ifndef WIFI_H_ +#define WIFI_H_ + +/** + * Enter WiFi network and Proxmox information +*/ + +const char* WIFI_SSID = ""; +const char* WIFI_PASS = ""; + +#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 627e413..b255036 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,3 +15,4 @@ framework = arduino lib_deps = leeseungcheol/ODROID-GO@^1.0.0 bblanchon/ArduinoJson@^6.20.1 +monitor_speed = 115200 diff --git a/src/json/retrieve.cpp b/src/json/retrieve.cpp new file mode 100644 index 0000000..140024d --- /dev/null +++ b/src/json/retrieve.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +// todo make the bottom part of these into one function +// ###################################### +// ###################################### +// ###################################### +// ###################################### +// ###################################### +JsonArray getNodeInfo() { + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/"; + 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(1024); + deserializeJson(doc, json); + JsonArray nodes = doc["data"].as(); + return nodes; + } + + displayError("Error getting data."); + return getNodeInfo(); +} + +JsonArray getContainerInfo(String node) { + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc"; + 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(1024); + deserializeJson(doc, json); + JsonArray nodes = doc["data"].as(); + return nodes; + } + + displayError("Error getting data."); + return getNodeInfo(); +} + +JsonArray getVMInfo(String node) { + HTTPClient http; + String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu"; + 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(1024); + deserializeJson(doc, json); + JsonArray nodes = doc["data"].as(); + return nodes; + } + + displayError("Error getting data."); + return getNodeInfo(); +} diff --git a/src/json/send.cpp b/src/json/send.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/json/utils.cpp b/src/json/utils.cpp new file mode 100644 index 0000000..86ecb81 --- /dev/null +++ b/src/json/utils.cpp @@ -0,0 +1,27 @@ +#include +#include + +/** + Get a specific node from an array of nodes +*/ +JsonObject getNode(String name, JsonArray nodes) { + for (JsonObject node : nodes) { + if (node["node"] == name) { + return node; + } + } + displayError("Node not found!"); + +} + +JsonObject getContainer(int id, JsonArray containers) { + for (JsonObject container : containers) { + Serial.println(id); + Serial.println(container["vmid"].as()); + if (container["vmid"].as() == id) { + return container; + } + } + displayError("Machine not found!"); + +} diff --git a/src/main.cpp b/src/main.cpp index 609f2dc..34ebe8e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,429 +1,11 @@ #include #include #include -#include #include -#include - - -int selectedItem = 0; - -String selectedNode; -// These ones are int as we use the ID instead of the name -int selectedVM; -int selectedLXC; - - -void listNodes(JsonArray nodes) { - GO.lcd.clearDisplay(); - GO.lcd.setCursor(0, 0); - int numItems = nodes.size(); - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { - GO.lcd.print("> "); - } - GO.lcd.println(nodes[i]["node"].as()); - } - - switch (buttonListener(numItems)) { - case 1: - Serial.println("selected " + selectedItem); - selectedNode = nodes[selectedItem]["node"].as(); - break; - case 2: - Serial.println("back"); - break; - default: - listNodes(nodes); - } -} - -void listContainers(JsonArray containers) { - GO.lcd.clearDisplay(); - GO.lcd.setCursor(0, 0); - int numItems = containers.size(); - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { - GO.lcd.print("> "); - } - GO.lcd.println(containers[i]["vmid"].as() + ": " + containers[i]["name"].as()); - } - - switch (buttonListener(numItems)) { - case 1: - Serial.println("selected " + selectedItem); - selectedLXC = containers[selectedItem]["vmid"].as(); - break; - case 2: - Serial.println("back"); - break; - default: - listContainers(containers); - } -} - -void listVMs(JsonArray vms) { - GO.lcd.clearDisplay(); - GO.lcd.setCursor(0, 0); - int numItems = vms.size(); - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { - GO.lcd.print("> "); - } - GO.lcd.println(vms[i]["vmid"].as() + ": " + vms[i]["name"].as()); - } - - switch (buttonListener(numItems)) { - case 1: - Serial.println("selected " + selectedItem); - selectedVM = vms[selectedItem]["vmid"].as(); - break; - case 2: - Serial.println("back"); - break; - default: - listVMs(vms); - } -} - -void printNodeStats(JsonObject node) { - String name = node["node"].as(); - int cpu = round(node["cpu"].as() * 100); - int threads = node["maxcpu"].as(); - String onlineStatus = node["status"].as(); - String mem = node["mem"].as(); - String maxmem = node["maxmem"].as(); - String disk = node["disk"].as(); - String maxdisk = node["maxdisk"].as(); - String uptime = node["uptime"].as(); - // these are strings for now because they could be way too big - - GO.lcd.fillScreen(WHITE); - GO.lcd.setCursor(0, 0); - GO.lcd.setTextColor(BLACK); - - GO.lcd.setTextSize(3); - GO.lcd.println(name); - GO.lcd.setTextSize(2); - GO.lcd.println("--------------------------"); - GO.lcd.println("Status: " + onlineStatus); - GO.lcd.println("Uptime: " + uptime + "s"); - GO.lcd.println("CPU: " + String(cpu) + "%"); - GO.lcd.println("Threads: " + String(threads)); - GO.lcd.println("RAM: " + mem); - GO.lcd.println("Max RAM: " + maxmem); - GO.lcd.println("Disk: " + disk); - GO.lcd.println("Max Disk: " + maxdisk); - -} - -void printContainerStats(JsonObject container) { - String name = container["name"].as(); - String id = container["vmid"].as(); - String onlineStatus = container["status"].as(); - String maxmem = container["maxmem"].as(); - String maxdisk = container["maxdisk"].as(); - String uptime = container["uptime"].as(); - // these are strings for now because they could be way too big - - GO.lcd.fillScreen(WHITE); - GO.lcd.setCursor(0, 0); - GO.lcd.setTextColor(BLACK); - - GO.lcd.setTextSize(3); - GO.lcd.println(id + ": " + name); - GO.lcd.setTextSize(2); - GO.lcd.println("--------------------------"); - GO.lcd.println("Status: " + onlineStatus); - GO.lcd.println("Uptime: " + uptime + "s"); - GO.lcd.println("Max RAM: " + maxmem); - GO.lcd.println("Max Disk: " + maxdisk); - -} - -void printVMStats(JsonObject vm) { - String name = vm["name"].as(); - String id = vm["vmid"].as(); - int cpu = round(vm["cpu"].as() * 100); - int cores = vm["cpus"].as(); - String onlineStatus = vm["status"].as(); - String mem = vm["mem"].as(); - String maxmem = vm["maxmem"].as(); - String maxdisk = vm["maxdisk"].as(); - String uptime = vm["uptime"].as(); - String netin = vm["netin"].as(); - String netout = vm["netout"].as(); - // these are strings for now because they could be way too big - - GO.lcd.fillScreen(WHITE); - GO.lcd.setCursor(0, 0); - GO.lcd.setTextColor(BLACK); - - GO.lcd.setTextSize(3); - GO.lcd.println(id + ": " + name); - GO.lcd.setTextSize(2); - GO.lcd.println("--------------------------"); - GO.lcd.println("Status: " + onlineStatus); - GO.lcd.println("Uptime: " + uptime + "s"); - GO.lcd.println("CPU: " + String(cpu) + "%"); - GO.lcd.println("Cores: " + String(cores)); - GO.lcd.println("RAM: " + mem); - GO.lcd.println("Max RAM: " + maxmem); - GO.lcd.println("Max Disk: " + maxdisk); - GO.lcd.println("Net In: " + netin); - GO.lcd.println("Net Out: " + netout); - - -} - - -void connectWiFi() { - WiFi.begin(WIFI_SSID, WIFI_PASS); - GO.lcd.print("Connecting"); - - while (WiFi.status() != WL_CONNECTED) { - delay(500); - Serial.print("."); - GO.lcd.print("."); - } - -} - -// Struct for static menu items such as on the main menu. Has the name of the menu item and a function to run when it is selected. -typedef struct { - char *name; - void (*function)(); -} MenuItem; - -// Array of the main menu items -MenuItem mainMenuItems[] = { - {"Node Information", &nodeInfo}, - {"Container Information", &containerInfo}, - {"VM Information", &vmInfo} -}; - - - -void nodeInfo() { - Serial.println("nodeinfo"); - while (true) { - printNodeStats(getNode(selectedNode, getNodeInfo())); - //printAllNodeCPU(getNodeInfo()); - delay(2000); - } -} - -void containerInfo() { - Serial.println("container info"); - JsonArray containerArray = getContainerInfo(selectedNode); - selectedItem = 0; - listContainers(containerArray); - JsonObject container = getContainer(selectedLXC, containerArray); - printContainerStats(container); - delay(1000); - - // only redraw screen if changed - while (true) { - if (getContainer(selectedLXC, containerArray) != container) { - containerInfo(); - } - } - -} - -void vmInfo() { - Serial.println("vm info"); - JsonArray vmArray = getVMInfo(selectedNode); - selectedItem = 0; - listVMs(vmArray); - while (true) { - printVMStats(getContainer(selectedVM, vmArray)); - delay(2000); - } - -} - -void mainMenu() { - GO.lcd.clearDisplay(); - GO.lcd.setCursor(0, 0); - int numItems = sizeof(mainMenuItems) / sizeof(MenuItem); - - for (int i = 0; i < numItems; i++) { - if (selectedItem == i) { - GO.lcd.print("> "); - } - GO.lcd.println(mainMenuItems[i].name); - } - - switch (buttonListener(numItems)) { - case 1: - Serial.println("selected " + selectedItem); - mainMenuItems[selectedItem].function(); - break; - case 2: - Serial.println("back"); - break; - default: - mainMenu(); - } - -} - -int buttonListener(int numItems) { - delay(200); - while (true) { - GO.update(); - if (GO.JOY_Y.isAxisPressed() == 1 && selectedItem < (numItems - 1)) { - selectedItem++; - break; - } - if (GO.JOY_Y.isAxisPressed() == 2 && selectedItem > 0) { - selectedItem--; - break; - } - if (GO.BtnA.isPressed() == 1) { - delay(300); - return 1; - } - if (GO.BtnB.isPressed() == 1) { - delay(300); - return 2; - } - - } - return 0; -} - -// todo make the bottom part of these into one function -// ###################################### -// ###################################### -// ###################################### -// ###################################### -// ###################################### -JsonArray getNodeInfo() { - HTTPClient http; - String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/"; - 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(1024); - deserializeJson(doc, json); - JsonArray nodes = doc["data"].as(); - return nodes; - } - - displayError("Error getting data."); - return getNodeInfo(); -} - -JsonArray getContainerInfo(String node) { - HTTPClient http; - String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/lxc"; - 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(1024); - deserializeJson(doc, json); - JsonArray nodes = doc["data"].as(); - return nodes; - } - - displayError("Error getting data."); - return getNodeInfo(); -} - -JsonArray getVMInfo(String node) { - HTTPClient http; - String apiAddress = PROXMOX_ADDRESS + "/api2/json/nodes/" + node + "/qemu"; - 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(1024); - deserializeJson(doc, json); - JsonArray nodes = doc["data"].as(); - return nodes; - } - - displayError("Error getting data."); - return getNodeInfo(); -} - - -/** - Get a specific node from an array of nodes -*/ -JsonObject getNode(String name, JsonArray nodes) { - for (JsonObject node : nodes) { - if (node["node"] == name) { - return node; - } - } - displayError("Node not found!"); - -} - -JsonObject getContainer(int id, JsonArray containers) { - for (JsonObject container : containers) { - Serial.println(id); - Serial.println(container["vmid"].as()); - if (container["vmid"].as() == id) { - return container; - } - } - displayError("Machine not found!"); - -} - - -/** - Display an error on the screen -*/ -void displayError(String message) { - GO.lcd.clearDisplay(); - GO.lcd.setCursor(0, 0); - GO.lcd.setTextSize(2); - GO.lcd.setTextColor(RED); - GO.lcd.print(message); - delay(3000); -} - - -void printAllNodeCPU(JsonArray nodes) { - GO.lcd.fillScreen(WHITE); - GO.lcd.setCursor(0, 0); - for (JsonObject node : nodes) { - Serial.print("CPU Usage for node "); - Serial.print(node["node"].as()); - Serial.print(": "); - Serial.println(String(round(node["cpu"].as() * 100)) + "%"); - - GO.lcd.setTextSize(2); - GO.lcd.setTextColor(BLACK); - GO.lcd.print("CPU Usage for node "); - GO.lcd.print(node["node"].as()); - GO.lcd.println(": "); - GO.lcd.println(String(round(node["cpu"].as() * 100)) + "%"); - } -} - +#include +#include +#include +#include void setup() { Serial.begin(115200); @@ -443,4 +25,4 @@ void loop() { mainMenu(); -} +} \ No newline at end of file diff --git a/src/manage.cpp b/src/manage.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/statistics.cpp b/src/statistics.cpp new file mode 100644 index 0000000..60f46db --- /dev/null +++ b/src/statistics.cpp @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include + + +void printNodeStats(JsonObject node) { + String name = node["node"].as(); + int cpu = round(node["cpu"].as() * 100); + int threads = node["maxcpu"].as(); + String onlineStatus = node["status"].as(); + String mem = node["mem"].as(); + String maxmem = node["maxmem"].as(); + String disk = node["disk"].as(); + String maxdisk = node["maxdisk"].as(); + String uptime = node["uptime"].as(); + // these are strings for now because they could be way too big + + GO.lcd.fillScreen(WHITE); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(BLACK); + + GO.lcd.setTextSize(3); + GO.lcd.println(name); + GO.lcd.setTextSize(2); + GO.lcd.println("--------------------------"); + GO.lcd.println("Status: " + onlineStatus); + GO.lcd.println("Uptime: " + uptime + "s"); + GO.lcd.println("CPU: " + String(cpu) + "%"); + GO.lcd.println("Threads: " + String(threads)); + GO.lcd.println("RAM: " + mem); + GO.lcd.println("Max RAM: " + maxmem); + GO.lcd.println("Disk: " + disk); + GO.lcd.println("Max Disk: " + maxdisk); + +} + +void printContainerStats(JsonObject container) { + String name = container["name"].as(); + String id = container["vmid"].as(); + String onlineStatus = container["status"].as(); + String maxmem = container["maxmem"].as(); + String maxdisk = container["maxdisk"].as(); + String uptime = container["uptime"].as(); + // these are strings for now because they could be way too big + + GO.lcd.fillScreen(WHITE); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(BLACK); + + GO.lcd.setTextSize(3); + GO.lcd.println(id + ": " + name); + GO.lcd.setTextSize(2); + GO.lcd.println("--------------------------"); + GO.lcd.println("Status: " + onlineStatus); + GO.lcd.println("Uptime: " + uptime + "s"); + GO.lcd.println("Max RAM: " + maxmem); + GO.lcd.println("Max Disk: " + maxdisk); + +} + +void printVMStats(JsonObject vm) { + String name = vm["name"].as(); + String id = vm["vmid"].as(); + int cpu = round(vm["cpu"].as() * 100); + int cores = vm["cpus"].as(); + String onlineStatus = vm["status"].as(); + String mem = vm["mem"].as(); + String maxmem = vm["maxmem"].as(); + String maxdisk = vm["maxdisk"].as(); + String uptime = vm["uptime"].as(); + String netin = vm["netin"].as(); + String netout = vm["netout"].as(); + // these are strings for now because they could be way too big + + GO.lcd.fillScreen(WHITE); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextColor(BLACK); + + GO.lcd.setTextSize(3); + GO.lcd.println(id + ": " + name); + GO.lcd.setTextSize(2); + GO.lcd.println("--------------------------"); + GO.lcd.println("Status: " + onlineStatus); + GO.lcd.println("Uptime: " + uptime + "s"); + GO.lcd.println("CPU: " + String(cpu) + "%"); + GO.lcd.println("Cores: " + String(cores)); + GO.lcd.println("RAM: " + mem); + GO.lcd.println("Max RAM: " + maxmem); + GO.lcd.println("Max Disk: " + maxdisk); + GO.lcd.println("Net In: " + netin); + GO.lcd.println("Net Out: " + netout); + + +} + + +void nodeInfo() { + Serial.println("nodeinfo"); + while (true) { + printNodeStats(getNode(selectedNode, getNodeInfo())); + delay(2000); + } +} + +void containerInfo() { + Serial.println("container info"); + JsonArray containerArray = getContainerInfo(selectedNode); + selectedItem = 0; + int selectedLXC = listContainers(containerArray); + JsonObject container = getContainer(selectedLXC, containerArray); + printContainerStats(container); + delay(1000); + + // only redraw screen if changed + while (true) { + if (getContainer(selectedLXC, containerArray) != container) { + containerInfo(); + } + } + +} + +void vmInfo() { + Serial.println("vm info"); + JsonArray vmArray = getVMInfo(selectedNode); + selectedItem = 0; + int selectedVM = listContainers(vmArray); + Serial.println("vm"); + Serial.println(selectedVM); + Serial.println(selectedVM); + Serial.println(selectedVM); + Serial.println(selectedVM); + + while (true) { + printVMStats(getContainer(selectedVM, vmArray)); + delay(2000); + } + +} \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..c302fe3 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,26 @@ +#include +#include +#include +/** + Display an error on the screen +*/ +void displayError(String message) { + GO.lcd.clearDisplay(); + GO.lcd.setCursor(0, 0); + GO.lcd.setTextSize(2); + GO.lcd.setTextColor(RED); + GO.lcd.print(message); + delay(3000); +} + +void connectWiFi() { + WiFi.begin(WIFI_SSID, WIFI_PASS); + GO.lcd.print("Connecting"); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + GO.lcd.print("."); + } + +} \ No newline at end of file