From ffd9bf002e1cf53f0d8b1f1e2ac1a4c2ea500395 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Thu, 23 Jan 2025 23:18:55 -0600 Subject: [PATCH 01/18] Added humidifier smartplug --- src/main/config.h | 19 ++++++++++--------- src/main/main.ino | 26 ++++++++++++-------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/main/config.h b/src/main/config.h index 7e2d55f..604fe4c 100644 --- a/src/main/config.h +++ b/src/main/config.h @@ -39,15 +39,16 @@ bool INTERRUPT_WITH_BITMAP = true; // Periodically show bi constexpr int INTERRUPT_BITMAP_TIME = 300000; // Check WiFi time (ms) // SMART PLUG CONFIGURATION -const char *intakePlugAlias = "plug_intake"; // Kasa plug alias (Intake) -const char *exhaustPlugAlias = "plug_exhaust"; // Kasa plug aliases (Exhaust) -constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) -constexpr float DESIRED_TEMP = 75.0; // Desired temperature in F -constexpr float DESIRED_HUMIDITY = 50.0; // Desired humidity in percentage -constexpr float DESIRED_CO2 = 800.0; // Desired CO2 level (ppm) -constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching -constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching -constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis to prevent rapid switching +const char *intakePlugAlias = "plug_intake"; // Kasa plug alias (Intake) +const char *exhaustPlugAlias = "plug_exhaust"; // Kasa plug aliases (Exhaust) +const char *humidifierPlugAlias = "plug_humidifier"; // Kasa plug aliases (Humidifier) +constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) +constexpr float DESIRED_TEMP = 75.0; // Desired temperature in F +constexpr float DESIRED_HUMIDITY = 50.0; // Desired humidity in percentage +constexpr float DESIRED_CO2 = 800.0; // Desired CO2 level (ppm) +constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching +constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching +constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis to prevent rapid switching // SERIAL CONFIGURATION constexpr int BAUD_RATE = 115200; // Baud rate diff --git a/src/main/main.ino b/src/main/main.ino index 7994d22..52bc09d 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -465,20 +465,18 @@ void loop() { setPlugState(intakePlug, false); // Turn off intake fan } -// // Humidity control logic -// if (humidity > DESIRED_HUMIDITY + HUMIDITY_HYSTERESIS) { // Humidity too high -// Serial.println(F("Humidity too high! Turning on exhaust fan...")); -// setPlugState(exhaustPlug, true); // Turn on exhaust fan -// } else if (humidity < DESIRED_HUMIDITY - HUMIDITY_HYSTERESIS) { // Humidity too low -// Serial.println(F("Humidity too low! Turning off intake and exhaust fans...")); -// setPlugState(intakePlug, false); // Turn off intake fan -// setPlugState(exhaustPlug, false); // Turn off exhaust fan -// // Optionally, activate a humidifier if available -// } else { -// // If humidity is within the target range, turn off fans to save energy -// setPlugState(exhaustPlug, false); // Turn off exhaust fan -// setPlugState(intakePlug, false); // Turn off intake fan -// } + // Humidity control logic + if (humidity > DESIRED_HUMIDITY + HUMIDITY_HYSTERESIS) { // Humidity too high + Serial.println(F("Humidity too high! Turning off humidifier...")); + setPlugState(humidifierPlugAlias, false); // Turn off humidifier + } else if (humidity < DESIRED_HUMIDITY - HUMIDITY_HYSTERESIS) { // Humidity too low + Serial.println(F("Humidity too low! Turning on humidifier...")); + setPlugState(humidifierPlugAlias, true); // Turn on humidifier + } else { + // If humidity is within the target range, turn off humidifier to save energy + setPlugState(humidifierPlugAlias, false); // Turn off humidifier + } + //TODO: Add CO2 levels } From bb1ed0112c10986cbdbd53c09150135564fcb63a Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Thu, 23 Jan 2025 23:19:20 -0600 Subject: [PATCH 02/18] Increased version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 8eb3891..4bccc27 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v5.0.0 \ No newline at end of file +v5.0.1 From 3e546b6c45e79d107b969da51c14cfac59efdfbe Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Thu, 23 Jan 2025 23:22:03 -0600 Subject: [PATCH 03/18] gitignore --- .gitignore | 5 +++++ src/main/.theia/launch.json | 19 ------------------- 2 files changed, 5 insertions(+), 19 deletions(-) delete mode 100644 src/main/.theia/launch.json diff --git a/.gitignore b/.gitignore index b484a1e..04b9d85 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,11 @@ *.egg-info +*.theia +*.theia/ +launch.json +src/main/.theia + venv/ .venv/ __pycache__/ diff --git a/src/main/.theia/launch.json b/src/main/.theia/launch.json deleted file mode 100644 index 1c48c5b..0000000 --- a/src/main/.theia/launch.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - "version": "0.2.0", - "configurations": [ - - { - "cwd": "${workspaceFolder}", - "executable": "./bin/executable.elf", - "name": "Debug with JLink", - "request": "launch", - "type": "cortex-debug", - "device": "", - "runToEntryPoint": "main", - "showDevDebugOutput": "none", - "servertype": "jlink" - } - ] -} From 9ca9495f6fb6d52989b51a13443e3e4fe824fe22 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Thu, 23 Jan 2025 23:24:47 -0600 Subject: [PATCH 04/18] Moved check wifi before plugs --- src/main/main.ino | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/main.ino b/src/main/main.ino index 52bc09d..b37d8f5 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -431,6 +431,23 @@ void loop() { updateOLED(co2, temperature, temperatureF, humidity); } + // Periodically check Wi-Fi status + if (currentTime - lastWiFiCheck >= WIFI_CHECK_INTERVAL) { + lastWiFiCheck = currentTime; + + if (WiFi.status() != WL_CONNECTED) { + Serial.println(F("Wi-Fi disconnected. Attempting to reconnect...")); + WiFi.reconnect(); // Attempt to reconnect + + if (WiFi.status() != WL_CONNECTED) { + Serial.println(F("Reconnection failed. Retrying full connection...")); + connectToWiFi(); // Fallback to full connection + } else { + Serial.println(F("Reconnected to Wi-Fi.")); + } + } + } + /* * Temperature Too High -> Turn on the exhaust fan, consider additional cooling (e.g., A/C). * Temperature Too Low -> Turn off the exhaust fan, possibly add a heater. @@ -480,23 +497,6 @@ void loop() { //TODO: Add CO2 levels } - // Periodically check Wi-Fi status - if (currentTime - lastWiFiCheck >= WIFI_CHECK_INTERVAL) { - lastWiFiCheck = currentTime; - - if (WiFi.status() != WL_CONNECTED) { - Serial.println(F("Wi-Fi disconnected. Attempting to reconnect...")); - WiFi.reconnect(); // Attempt to reconnect - - if (WiFi.status() != WL_CONNECTED) { - Serial.println(F("Reconnection failed. Retrying full connection...")); - connectToWiFi(); // Fallback to full connection - } else { - Serial.println(F("Reconnected to Wi-Fi.")); - } - } - } - // Periodically show bitmap if (INTERRUPT_WITH_BITMAP) { if (currentTime - lastBitmapCheck >= INTERRUPT_BITMAP_TIME) { From 07228ed0b3a725b605500552c80345c435ae40c0 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Thu, 23 Jan 2025 23:30:32 -0600 Subject: [PATCH 05/18] Changed library URL --- docs/README.md | 4 ++-- src/main/main.ino | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 1ad678b..cd3103c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -126,7 +126,7 @@ required libraries listed in the `DEPENDENCIES` section in [`main.ino`](/src/mai #### External Libraries -- [KasaSmartPlug Github](https://github.com/kj831ca/KasaSmartPlug) +- [KasaSmartPlug Github](https://github.com/ConnerWill/KasaSmartPlug) --- @@ -191,6 +191,6 @@ The 3D model files are located under the [3D-models](/3D-models) directory. * https://www.thingiverse.com/thing:4521313 * https://www.thingiverse.com/thing:2893581 * https://javl.github.io/image2cpp -* https://github.com/kj831ca/KasaSmartPlug +* https://github.com/ConnerWill/KasaSmartPlug --- diff --git a/src/main/main.ino b/src/main/main.ino index b37d8f5..ad6591c 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -12,7 +12,7 @@ #include #include #include -#include "KasaSmartPlug.h" // KASA TP-link smart plug library: https://github.com/kj831ca/KasaSmartPlug +#include "KasaSmartPlug.h" // KASA TP-link smart plug library: https://github.com/ConnerWill/KasaSmartPlug #include "config.h" // Include config header file #include "bitmap.h" // Include bitmap header file // ============================================================================ From 7831590d92191a5157c6c5834ca047f3093fecb9 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 09:16:13 -0600 Subject: [PATCH 06/18] Increased version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 4bccc27..6b7ace3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v5.0.1 +v5.1.0 From 56766e291490601a32d3c2321ccc5b53c2e695b7 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 12:44:33 -0600 Subject: [PATCH 07/18] Added showing the degree symbol --- src/main/main.ino | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/main.ino b/src/main/main.ino index ad6591c..a9504e8 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -327,13 +327,17 @@ void updateOLED(float co2, float temperature, float temperatureF, float humidity display.setCursor(0, 16); display.print("Temp: "); display.print(temperature); - display.println(" C"); + display.print(" "); // print space + display.write(0xF8); // Print the degrees symbol + display.println("C"); // Temperature display.setCursor(0, 26); display.print("Temp: "); display.print(temperatureF); - display.println(" F"); + display.print(" "); // print space + display.write(0xF8); // Print the degrees symbol + display.println("F"); // Humidity display.setCursor(0, 36); From 65d00783ed1b6227817ba9f34b42d1de6c2ed4a4 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 13:44:22 -0600 Subject: [PATCH 08/18] Changed startup text to be centered --- src/main/main.ino | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/main.ino b/src/main/main.ino index a9504e8..b007883 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -254,19 +254,25 @@ void initOLED() { // Function to show startup display void showStart() { + int16_t text_x, text_y; + uint16_t text_w, text_h; + + // Clear display, set size display.clearDisplay(); - display.setTextSize(3); + display.setTextSize(2); display.setTextColor(SSD1306_WHITE); - display.setCursor(32, 16); - display.println(STARTUP_TEXT); - display.display(); - // Scroll diag right - //display.startscrolldiagright(0x00, 0x07); - // Scroll left - display.startscrollleft(0x00, 0x0F); + // Calculate text bounds (0, 0 is a dummy position for now) + display.getTextBounds(STARTUP_TEXT, 0, 0, &text_x, &text_y, &text_w, &text_h); + + // Calculate coordinates to center the text + int16_t x = (SCREEN_WIDTH - text_w) / 2; + int16_t y = (SCREEN_HEIGHT - text_h) / 2; + + display.setCursor(x, y); + display.print(text); + display.display(); delay(SCREEN_STARTUP_DISPLAY_TIME); - display.stopscroll(); display.clearDisplay(); } From 3f93377cc20134453c9631e617f6e17d10717dd3 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 13:55:41 -0600 Subject: [PATCH 09/18] display.cp437(true); // Use correct CP437 character codes --- src/main/main.ino | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/main.ino b/src/main/main.ino index b007883..7879c8f 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -246,9 +246,10 @@ void initOLED() { } // Default text settings - display.clearDisplay(); + display.cp437(true); // Use correct CP437 character codes display.setTextSize(1); display.setTextColor(SSD1306_WHITE); + display.clearDisplay(); } From 5de5cfbe5f58b5e7f8764b84ac70cbdff4b8f3ff Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 14:10:48 -0600 Subject: [PATCH 10/18] Added different temp and humidity values for veg and flower --- src/main/config.h | 25 +++++++++------ src/main/main.ino | 78 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 70 insertions(+), 33 deletions(-) diff --git a/src/main/config.h b/src/main/config.h index 604fe4c..3c0adbf 100644 --- a/src/main/config.h +++ b/src/main/config.h @@ -39,16 +39,21 @@ bool INTERRUPT_WITH_BITMAP = true; // Periodically show bi constexpr int INTERRUPT_BITMAP_TIME = 300000; // Check WiFi time (ms) // SMART PLUG CONFIGURATION -const char *intakePlugAlias = "plug_intake"; // Kasa plug alias (Intake) -const char *exhaustPlugAlias = "plug_exhaust"; // Kasa plug aliases (Exhaust) -const char *humidifierPlugAlias = "plug_humidifier"; // Kasa plug aliases (Humidifier) -constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) -constexpr float DESIRED_TEMP = 75.0; // Desired temperature in F -constexpr float DESIRED_HUMIDITY = 50.0; // Desired humidity in percentage -constexpr float DESIRED_CO2 = 800.0; // Desired CO2 level (ppm) -constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching -constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching -constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis to prevent rapid switching +const char *intakePlugAlias = "plug_intake"; // Kasa plug alias (Intake) +const char *exhaustPlugAlias = "plug_exhaust"; // Kasa plug aliases (Exhaust) +const char *humidifierPlugAlias = "plug_humidifier"; // Kasa plug aliases (Humidifier) +const char *lightPlugAlias = "plug_light"; // Kasa plug aliases (Lights) +constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) +bool FLOWER = false; // Set to true to set flower mode //TODO: Link this to a physical switch +constexpr float DESIRED_TEMP_VEG = 80.0; // Desired temperature in F (veg) +constexpr float DESIRED_HUMIDITY_VEG = 65.0; // Desired humidity in percentage (veg) +constexpr float DESIRED_CO2_VEG = 800.0; // Desired CO2 level (ppm) (veg) +constexpr float DESIRED_TEMP_FLOWER = 71.0; // Desired temperature in F (flower) +constexpr float DESIRED_HUMIDITY_FLOWER = 50.0; // Desired humidity in percentage (flower) +constexpr float DESIRED_CO2_FLOWER = 800.0; // Desired CO2 level (ppm) (flower) +constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching +constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching +constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis to prevent rapid switching // SERIAL CONFIGURATION constexpr int BAUD_RATE = 115200; // Baud rate diff --git a/src/main/main.ino b/src/main/main.ino index 7879c8f..865a9b2 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -478,31 +478,63 @@ void loop() { float temperatureF = celsiusToFahrenheit(temperature); float humidity = readHumidity(); + // TODO: Link if we are in flower to a physical switch + // TODO: simplify so there is not 2 sets of if statements. Dynamic desired temp and humidity values + // // Temperature control logic - if (temperatureF > DESIRED_TEMP + TEMP_HYSTERESIS) { // Temp too high - Serial.println(F("Temperature too high! Turning on intake and exhaust fans...")); - setPlugState(exhaustPlug, true); // Turn on exhaust fan - setPlugState(intakePlug, true); // Turn on intake fan - } else if (temperatureF < DESIRED_TEMP - TEMP_HYSTERESIS) { // Temp too low - Serial.println(F("Temperature too low! Turning off intake and exhaust fans...")); - setPlugState(exhaustPlug, false); // Turn off exhaust fan - setPlugState(intakePlug, false); // Turn off intake fan - } else { - // If temperature is within the target range, turn off fans to save energy - setPlugState(exhaustPlug, false); // Turn off exhaust fan - setPlugState(intakePlug, false); // Turn off intake fan - } + if (FLOWER) { // FLOWER + if (temperatureF > DESIRED_TEMP_FLOWER + TEMP_HYSTERESIS) { // Temp too high + Serial.println(F("Temperature too high! Turning on intake and exhaust fans...")); + setPlugState(exhaustPlug, true); // Turn on exhaust fan + setPlugState(intakePlug, true); // Turn on intake fan + } else if (temperatureF < DESIRED_TEMP_FLOWER - TEMP_HYSTERESIS) { // Temp too low + Serial.println(F("Temperature too low! Turning off intake and exhaust fans...")); + setPlugState(exhaustPlug, false); // Turn off exhaust fan + setPlugState(intakePlug, false); // Turn off intake fan + } else { + // If temperature is within the target range, turn off fans to save energy + setPlugState(exhaustPlug, false); // Turn off exhaust fan + setPlugState(intakePlug, false); // Turn off intake fan + } + + // Humidity control logic + if (humidity > DESIRED_HUMIDITY_FLOWER + HUMIDITY_HYSTERESIS) { // Humidity too high + Serial.println(F("Humidity too high! Turning off humidifier...")); + setPlugState(humidifierPlugAlias, false); // Turn off humidifier + } else if (humidity < DESIRED_HUMIDITY_FLOWER - HUMIDITY_HYSTERESIS) { // Humidity too low + Serial.println(F("Humidity too low! Turning on humidifier...")); + setPlugState(humidifierPlugAlias, true); // Turn on humidifier + } else { + // If humidity is within the target range, turn off humidifier to save energy + setPlugState(humidifierPlugAlias, false); // Turn off humidifier + } - // Humidity control logic - if (humidity > DESIRED_HUMIDITY + HUMIDITY_HYSTERESIS) { // Humidity too high - Serial.println(F("Humidity too high! Turning off humidifier...")); - setPlugState(humidifierPlugAlias, false); // Turn off humidifier - } else if (humidity < DESIRED_HUMIDITY - HUMIDITY_HYSTERESIS) { // Humidity too low - Serial.println(F("Humidity too low! Turning on humidifier...")); - setPlugState(humidifierPlugAlias, true); // Turn on humidifier - } else { - // If humidity is within the target range, turn off humidifier to save energy - setPlugState(humidifierPlugAlias, false); // Turn off humidifier + } else { // VEG + if (temperatureF > DESIRED_TEMP_VEG + TEMP_HYSTERESIS) { // Temp too high + Serial.println(F("Temperature too high! Turning on intake and exhaust fans...")); + setPlugState(exhaustPlug, true); // Turn on exhaust fan + setPlugState(intakePlug, true); // Turn on intake fan + } else if (temperatureF < DESIRED_TEMP_VEG - TEMP_HYSTERESIS) { // Temp too low + Serial.println(F("Temperature too low! Turning off intake and exhaust fans...")); + setPlugState(exhaustPlug, false); // Turn off exhaust fan + setPlugState(intakePlug, false); // Turn off intake fan + } else { + // If temperature is within the target range, turn off fans to save energy + setPlugState(exhaustPlug, false); // Turn off exhaust fan + setPlugState(intakePlug, false); // Turn off intake fan + } + + // Humidity control logic + if (humidity > DESIRED_HUMIDITY_VEG + HUMIDITY_HYSTERESIS) { // Humidity too high + Serial.println(F("Humidity too high! Turning off humidifier...")); + setPlugState(humidifierPlugAlias, false); // Turn off humidifier + } else if (humidity < DESIRED_HUMIDITY_VEG - HUMIDITY_HYSTERESIS) { // Humidity too low + Serial.println(F("Humidity too low! Turning on humidifier...")); + setPlugState(humidifierPlugAlias, true); // Turn on humidifier + } else { + // If humidity is within the target range, turn off humidifier to save energy + setPlugState(humidifierPlugAlias, false); // Turn off humidifier + } } //TODO: Add CO2 levels From 91b91f0aa48b07bd71c5d7b80e31b746b54f5050 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 14:14:37 -0600 Subject: [PATCH 11/18] Adjusted values for veg and flower --- src/main/config.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/config.h b/src/main/config.h index 3c0adbf..95c9ecd 100644 --- a/src/main/config.h +++ b/src/main/config.h @@ -45,12 +45,12 @@ const char *humidifierPlugAlias = "plug_humidifier"; // Kasa plug aliase const char *lightPlugAlias = "plug_light"; // Kasa plug aliases (Lights) constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) bool FLOWER = false; // Set to true to set flower mode //TODO: Link this to a physical switch -constexpr float DESIRED_TEMP_VEG = 80.0; // Desired temperature in F (veg) +constexpr float DESIRED_TEMP_VEG = 75.0; // Desired temperature in F (veg) constexpr float DESIRED_HUMIDITY_VEG = 65.0; // Desired humidity in percentage (veg) constexpr float DESIRED_CO2_VEG = 800.0; // Desired CO2 level (ppm) (veg) -constexpr float DESIRED_TEMP_FLOWER = 71.0; // Desired temperature in F (flower) +constexpr float DESIRED_TEMP_FLOWER = 70.0; // Desired temperature in F (flower) constexpr float DESIRED_HUMIDITY_FLOWER = 50.0; // Desired humidity in percentage (flower) -constexpr float DESIRED_CO2_FLOWER = 800.0; // Desired CO2 level (ppm) (flower) +constexpr float DESIRED_CO2_FLOWER = 1000.0; // Desired CO2 level (ppm) (flower) constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis to prevent rapid switching From 1a95e217754175de3c29cbbd8bd032b590e24b49 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 14:18:51 -0600 Subject: [PATCH 12/18] Changed default plug aliases --- src/main/config.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/config.h b/src/main/config.h index 95c9ecd..392f1ee 100644 --- a/src/main/config.h +++ b/src/main/config.h @@ -39,21 +39,21 @@ bool INTERRUPT_WITH_BITMAP = true; // Periodically show bi constexpr int INTERRUPT_BITMAP_TIME = 300000; // Check WiFi time (ms) // SMART PLUG CONFIGURATION -const char *intakePlugAlias = "plug_intake"; // Kasa plug alias (Intake) -const char *exhaustPlugAlias = "plug_exhaust"; // Kasa plug aliases (Exhaust) -const char *humidifierPlugAlias = "plug_humidifier"; // Kasa plug aliases (Humidifier) -const char *lightPlugAlias = "plug_light"; // Kasa plug aliases (Lights) -constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) -bool FLOWER = false; // Set to true to set flower mode //TODO: Link this to a physical switch -constexpr float DESIRED_TEMP_VEG = 75.0; // Desired temperature in F (veg) -constexpr float DESIRED_HUMIDITY_VEG = 65.0; // Desired humidity in percentage (veg) -constexpr float DESIRED_CO2_VEG = 800.0; // Desired CO2 level (ppm) (veg) -constexpr float DESIRED_TEMP_FLOWER = 70.0; // Desired temperature in F (flower) -constexpr float DESIRED_HUMIDITY_FLOWER = 50.0; // Desired humidity in percentage (flower) -constexpr float DESIRED_CO2_FLOWER = 1000.0; // Desired CO2 level (ppm) (flower) -constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching -constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching -constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis to prevent rapid switching +const char *intakePlugAlias = "tent1_intake"; // Kasa plug alias (Intake) +const char *exhaustPlugAlias = "tent1_exhaust"; // Kasa plug aliases (Exhaust) +const char *humidifierPlugAlias = "tent1_humidifier"; // Kasa plug aliases (Humidifier) +const char *lightPlugAlias = "tent1_light"; // Kasa plug aliases (Lights) +constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) +bool FLOWER = false; // Set to true to set flower mode //TODO: Link this to a physical switch +constexpr float DESIRED_TEMP_VEG = 75.0; // Desired temperature in F (veg) +constexpr float DESIRED_HUMIDITY_VEG = 65.0; // Desired humidity in percentage (veg) +constexpr float DESIRED_CO2_VEG = 800.0; // Desired CO2 level (ppm) (veg) +constexpr float DESIRED_TEMP_FLOWER = 70.0; // Desired temperature in F (flower) +constexpr float DESIRED_HUMIDITY_FLOWER = 50.0; // Desired humidity in percentage (flower) +constexpr float DESIRED_CO2_FLOWER = 1000.0; // Desired CO2 level (ppm) (flower) +constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching +constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching +constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis to prevent rapid switching // SERIAL CONFIGURATION constexpr int BAUD_RATE = 115200; // Baud rate From 9b2966dfa682db159d9250ba0f13ee4c44187c53 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 14:20:39 -0600 Subject: [PATCH 13/18] Adjusted values for veg and flower --- src/main/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/config.h b/src/main/config.h index 392f1ee..5bb7fd4 100644 --- a/src/main/config.h +++ b/src/main/config.h @@ -49,7 +49,7 @@ constexpr float DESIRED_TEMP_VEG = 75.0; // Desired tempera constexpr float DESIRED_HUMIDITY_VEG = 65.0; // Desired humidity in percentage (veg) constexpr float DESIRED_CO2_VEG = 800.0; // Desired CO2 level (ppm) (veg) constexpr float DESIRED_TEMP_FLOWER = 70.0; // Desired temperature in F (flower) -constexpr float DESIRED_HUMIDITY_FLOWER = 50.0; // Desired humidity in percentage (flower) +constexpr float DESIRED_HUMIDITY_FLOWER = 45.0; // Desired humidity in percentage (flower) constexpr float DESIRED_CO2_FLOWER = 1000.0; // Desired CO2 level (ppm) (flower) constexpr float TEMP_HYSTERESIS = 1.0; // Temperature hysteresis to prevent rapid switching constexpr float HUMIDITY_HYSTERESIS = 5.0; // Humidity hysteresis to prevent rapid switching From 806508780b57f8e83f8a7923b04623ec0a871604 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 14:58:12 -0600 Subject: [PATCH 14/18] Added functions to set humidity --- src/main/bitmap.h | 3 +- src/main/config.h | 1 + src/main/main.ino | 108 +++++++++++++++++----------------------------- 3 files changed, 43 insertions(+), 69 deletions(-) diff --git a/src/main/bitmap.h b/src/main/bitmap.h index 129c35e..79db29c 100644 --- a/src/main/bitmap.h +++ b/src/main/bitmap.h @@ -77,4 +77,5 @@ const unsigned char bitmap_image[] PROGMEM = { 0x77, 0x77, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff }; -#endif \ No newline at end of file +#endif +//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber diff --git a/src/main/config.h b/src/main/config.h index 5bb7fd4..908aa0c 100644 --- a/src/main/config.h +++ b/src/main/config.h @@ -58,3 +58,4 @@ constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis // SERIAL CONFIGURATION constexpr int BAUD_RATE = 115200; // Baud rate // ============================================================================ +//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber diff --git a/src/main/main.ino b/src/main/main.ino index 865a9b2..9bc9953 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -167,7 +167,38 @@ void setPlugState(KASASmartPlug* plug, bool state) { } } -//TODO: Function to get plug state +// Function to control fans based on temperature +void handleTemperature(float temperatureF, float desiredTemp, const char* mode) { + if (temperatureF > desiredTemp + TEMP_HYSTERESIS) { // Temp too high + Serial.printf("Temperature too high in %s mode! Turning on intake and exhaust fans...\n", mode); // + setPlugState(exhaustPlug, true); // Turn on exhaust fan + setPlugState(intakePlug, true); // Turn on intake fan + + } else if (temperatureF < desiredTemp - TEMP_HYSTERESIS) { // Temp too low + Serial.printf("Temperature too low in %s mode! Turning off intake and exhaust fans...\n", mode); // + setPlugState(exhaustPlug, false); // Turn off exhaust fan + setPlugState(intakePlug, false); // Turn off intake fan + + } else { // Temperature within range + setPlugState(exhaustPlug, false); // Turn off exhaust fan to save energy + setPlugState(intakePlug, false); // Turn off intake fan to save energy + } +} + +// Function to control humidifier based on humidity +void handleHumidity(float humidity, float desiredHumidity, const char* mode) { + if (humidity > desiredHumidity + HUMIDITY_HYSTERESIS) { // Humidity too high + Serial.printf("Humidity too high in %s mode! Turning off humidifier...\n", mode); // + setPlugState(humidifierPlugAlias, false); // Turn off humidifier + + } else if (humidity < desiredHumidity - HUMIDITY_HYSTERESIS) { // Humidity too low + Serial.printf("Humidity too low in %s mode! Turning on humidifier...\n", mode); // + setPlugState(humidifierPlugAlias, true); // Turn on humidifier + + } else { // Humidity within range + setPlugState(humidifierPlugAlias, false); // Turn off humidifier to save energy + } +} // ------------------------------------- // WIFI Functions @@ -459,15 +490,6 @@ void loop() { } } -/* - * Temperature Too High -> Turn on the exhaust fan, consider additional cooling (e.g., A/C). - * Temperature Too Low -> Turn off the exhaust fan, possibly add a heater. - * Humidity Too High -> Turn on the exhaust fan to vent humid air, or use a dehumidifier. - * Humidity Too Low -> Turn off the exhaust fan, reduce intake, and add a humidifier if needed. - * CO2 Too High -> Turn on the exhaust fan to vent excess CO2. - * CO2 Too Low -> Turn off the exhaust fan to retain CO2, or add a CO2 source. -*/ - // Update Smart plugs if (currentTime - lastPlugCheck >= SMARTPLUG_UPDATE_TIME) { lastPlugCheck = currentTime; @@ -478,65 +500,14 @@ void loop() { float temperatureF = celsiusToFahrenheit(temperature); float humidity = readHumidity(); - // TODO: Link if we are in flower to a physical switch - // TODO: simplify so there is not 2 sets of if statements. Dynamic desired temp and humidity values - // - // Temperature control logic - if (FLOWER) { // FLOWER - if (temperatureF > DESIRED_TEMP_FLOWER + TEMP_HYSTERESIS) { // Temp too high - Serial.println(F("Temperature too high! Turning on intake and exhaust fans...")); - setPlugState(exhaustPlug, true); // Turn on exhaust fan - setPlugState(intakePlug, true); // Turn on intake fan - } else if (temperatureF < DESIRED_TEMP_FLOWER - TEMP_HYSTERESIS) { // Temp too low - Serial.println(F("Temperature too low! Turning off intake and exhaust fans...")); - setPlugState(exhaustPlug, false); // Turn off exhaust fan - setPlugState(intakePlug, false); // Turn off intake fan - } else { - // If temperature is within the target range, turn off fans to save energy - setPlugState(exhaustPlug, false); // Turn off exhaust fan - setPlugState(intakePlug, false); // Turn off intake fan - } - - // Humidity control logic - if (humidity > DESIRED_HUMIDITY_FLOWER + HUMIDITY_HYSTERESIS) { // Humidity too high - Serial.println(F("Humidity too high! Turning off humidifier...")); - setPlugState(humidifierPlugAlias, false); // Turn off humidifier - } else if (humidity < DESIRED_HUMIDITY_FLOWER - HUMIDITY_HYSTERESIS) { // Humidity too low - Serial.println(F("Humidity too low! Turning on humidifier...")); - setPlugState(humidifierPlugAlias, true); // Turn on humidifier - } else { - // If humidity is within the target range, turn off humidifier to save energy - setPlugState(humidifierPlugAlias, false); // Turn off humidifier - } - - } else { // VEG - if (temperatureF > DESIRED_TEMP_VEG + TEMP_HYSTERESIS) { // Temp too high - Serial.println(F("Temperature too high! Turning on intake and exhaust fans...")); - setPlugState(exhaustPlug, true); // Turn on exhaust fan - setPlugState(intakePlug, true); // Turn on intake fan - } else if (temperatureF < DESIRED_TEMP_VEG - TEMP_HYSTERESIS) { // Temp too low - Serial.println(F("Temperature too low! Turning off intake and exhaust fans...")); - setPlugState(exhaustPlug, false); // Turn off exhaust fan - setPlugState(intakePlug, false); // Turn off intake fan - } else { - // If temperature is within the target range, turn off fans to save energy - setPlugState(exhaustPlug, false); // Turn off exhaust fan - setPlugState(intakePlug, false); // Turn off intake fan - } - - // Humidity control logic - if (humidity > DESIRED_HUMIDITY_VEG + HUMIDITY_HYSTERESIS) { // Humidity too high - Serial.println(F("Humidity too high! Turning off humidifier...")); - setPlugState(humidifierPlugAlias, false); // Turn off humidifier - } else if (humidity < DESIRED_HUMIDITY_VEG - HUMIDITY_HYSTERESIS) { // Humidity too low - Serial.println(F("Humidity too low! Turning on humidifier...")); - setPlugState(humidifierPlugAlias, true); // Turn on humidifier - } else { - // If humidity is within the target range, turn off humidifier to save energy - setPlugState(humidifierPlugAlias, false); // Turn off humidifier - } - } + // Determine mode (Flower or Veg) and set desired values + const char* mode = FLOWER ? "FLOWER" : "VEG"; + float desiredTemp = FLOWER ? DESIRED_TEMP_FLOWER : DESIRED_TEMP_VEG; + float desiredHumidity = FLOWER ? DESIRED_HUMIDITY_FLOWER : DESIRED_HUMIDITY_VEG; + // Handle temperature and humidity + handleTemperature(temperatureF, desiredTemp, mode); + handleHumidity(humidity, desiredHumidity, mode); //TODO: Add CO2 levels } @@ -549,3 +520,4 @@ void loop() { } } // ============================================================================ +//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber From 6ca880c57b58a22c3f3b66776a7a98df200cfc24 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 15:01:46 -0600 Subject: [PATCH 15/18] Increased version --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6b7ace3..346d9ca 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v5.1.0 +v5.1.1 From b0a098881ecc9a3c29e68fc182ed5bd523ed76c9 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Fri, 24 Jan 2025 15:05:30 -0600 Subject: [PATCH 16/18] Removed co2 TODO --- src/main/main.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/main.ino b/src/main/main.ino index 9bc9953..e7a4f48 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -508,7 +508,6 @@ void loop() { // Handle temperature and humidity handleTemperature(temperatureF, desiredTemp, mode); handleHumidity(humidity, desiredHumidity, mode); - //TODO: Add CO2 levels } // Periodically show bitmap From d7b730a8113e6aa5607fcb6aed16468910c4165e Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Sun, 26 Jan 2025 12:43:45 -0600 Subject: [PATCH 17/18] init humidifier --- src/main/main.ino | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/main.ino b/src/main/main.ino index e7a4f48..f6598c6 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -123,6 +123,9 @@ void initSmartPlugs() { } else if (strcmp(plug->alias, exhaustPlugAlias) == 0) { exhaustPlug = plug; Serial.println("Exhaust plug initialized."); + } else if (strcmp(plug->alias, humidifierPlugAlias) == 0) { + humidifierPlugAlias = plug; + Serial.println("Humidifier plug initialized."); } } @@ -145,6 +148,15 @@ void initSmartPlugs() { display.display(); delay(1000); } + if (humidifierPlugAlias == NULL) { + Serial.println("Error: Humidifier plug not found!"); + + display.clearDisplay(); + display.setCursor(0, 0); + display.print("ERROR: Humidifier plug not found"); + display.display(); + delay(1000); + } } // Function to turn a plug on or off From cd8babff0343ecd51b73b6c2a17cdb5834ef6c50 Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Sun, 26 Jan 2025 16:58:41 -0600 Subject: [PATCH 18/18] Fixed humidity plug errors. Changed default settings --- src/main/bitmap.h | 2 +- src/main/config.h | 10 +++++----- src/main/main.ino | 19 ++++++++++--------- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/bitmap.h b/src/main/bitmap.h index 79db29c..8e1b14b 100644 --- a/src/main/bitmap.h +++ b/src/main/bitmap.h @@ -78,4 +78,4 @@ const unsigned char bitmap_image[] PROGMEM = { }; #endif -//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber +//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber \ No newline at end of file diff --git a/src/main/config.h b/src/main/config.h index 908aa0c..de7091b 100644 --- a/src/main/config.h +++ b/src/main/config.h @@ -10,7 +10,7 @@ // ============================================================================ // WIFI CONFIGURATION constexpr char WIFI_SSID[] = ""; // Wi-Fi SSID -constexpr char WIFI_PASSWORD[] = ""; // Wi-Fi password +constexpr char WIFI_PASSWORD[] = "!"; // Wi-Fi password constexpr char WIFI_HOSTNAME[] = "esp32-plant"; // Hostname constexpr int WIFI_TIMEOUT_TIME = 30000; // Timeout if unable to connect to WiFi (ms) constexpr int WIFI_CHECK_INTERVAL = 5000; // Check WiFi time (ms) @@ -28,7 +28,7 @@ constexpr int SCREEN_WIDTH = 128; // OLED display width, constexpr int SCREEN_HEIGHT = 64; // OLED display height, in pixels constexpr uint8_t SCREEN_ADDRESS = 0x3C; // Address of OLED display (could also be '0x3D' depending on screen resolution) constexpr int SCREEN_UPDATE_TIME = 1000; // Time to wait before updating OLED (ms) -constexpr int SCREEN_STARTUP_DISPLAY_TIME = 4000; // Startup screen delay time (ms) +constexpr int SCREEN_STARTUP_DISPLAY_TIME = 3000; // Startup screen delay time (ms) bool SHOW_STARTUP = true; // Set to true to show the startup sequence bool SHOW_BITMAP = true; // Set to true to show the bitmap bool SHOW_CUSTOM_TEXT = true; // Set to true to show custom text @@ -42,11 +42,11 @@ constexpr int INTERRUPT_BITMAP_TIME = 300000; // Check WiFi time (ms) const char *intakePlugAlias = "tent1_intake"; // Kasa plug alias (Intake) const char *exhaustPlugAlias = "tent1_exhaust"; // Kasa plug aliases (Exhaust) const char *humidifierPlugAlias = "tent1_humidifier"; // Kasa plug aliases (Humidifier) -const char *lightPlugAlias = "tent1_light"; // Kasa plug aliases (Lights) +//const char *lightPlugAlias = "tent1_light"; // Kasa plug aliases (Lights) constexpr int SMARTPLUG_UPDATE_TIME = 30000; // Update smart plugs time (ms) bool FLOWER = false; // Set to true to set flower mode //TODO: Link this to a physical switch constexpr float DESIRED_TEMP_VEG = 75.0; // Desired temperature in F (veg) -constexpr float DESIRED_HUMIDITY_VEG = 65.0; // Desired humidity in percentage (veg) +constexpr float DESIRED_HUMIDITY_VEG = 60.0; // Desired humidity in percentage (veg) constexpr float DESIRED_CO2_VEG = 800.0; // Desired CO2 level (ppm) (veg) constexpr float DESIRED_TEMP_FLOWER = 70.0; // Desired temperature in F (flower) constexpr float DESIRED_HUMIDITY_FLOWER = 45.0; // Desired humidity in percentage (flower) @@ -58,4 +58,4 @@ constexpr float CO2_HYSTERESIS = 100.0; // CO2 hysteresis // SERIAL CONFIGURATION constexpr int BAUD_RATE = 115200; // Baud rate // ============================================================================ -//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber +//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber \ No newline at end of file diff --git a/src/main/main.ino b/src/main/main.ino index f6598c6..5dbe956 100644 --- a/src/main/main.ino +++ b/src/main/main.ino @@ -26,6 +26,7 @@ AsyncWebServer server(SERVER_PORT); // Define serv KASAUtil kasaUtil; // Kasa utility object KASASmartPlug *intakePlug = NULL; // Smart plug pointers (Intake) KASASmartPlug *exhaustPlug = NULL; // Smart plug pointers (Exhaust) +KASASmartPlug *humidifierPlug = NULL; // Smart plug pointers (Humidifier) // ============================================================================ // ============================================================================ @@ -124,12 +125,13 @@ void initSmartPlugs() { exhaustPlug = plug; Serial.println("Exhaust plug initialized."); } else if (strcmp(plug->alias, humidifierPlugAlias) == 0) { - humidifierPlugAlias = plug; + humidifierPlug = plug; Serial.println("Humidifier plug initialized."); } } // Check if plugs were found + //TODO: Could clean this up if (intakePlug == NULL) { Serial.println("Error: Intake plug not found!"); @@ -148,7 +150,7 @@ void initSmartPlugs() { display.display(); delay(1000); } - if (humidifierPlugAlias == NULL) { + if (humidifierPlug == NULL) { Serial.println("Error: Humidifier plug not found!"); display.clearDisplay(); @@ -162,8 +164,7 @@ void initSmartPlugs() { // Function to turn a plug on or off void setPlugState(KASASmartPlug* plug, bool state) { // Setting variable for printing. otherwise dont need this - //TODO: Figure out how to turn this into a string - KASASmartPlug *plugAlias = kasaUtil.GetSmartPlug(plug->alias); + //KASASmartPlug *plugAlias = kasaUtil.GetSmartPlug(plug->alias); if (plug == NULL) { //Serial.printf("Error: Could not find plug with alias '%s'\n", plugAlias); @@ -201,14 +202,14 @@ void handleTemperature(float temperatureF, float desiredTemp, const char* mode) void handleHumidity(float humidity, float desiredHumidity, const char* mode) { if (humidity > desiredHumidity + HUMIDITY_HYSTERESIS) { // Humidity too high Serial.printf("Humidity too high in %s mode! Turning off humidifier...\n", mode); // - setPlugState(humidifierPlugAlias, false); // Turn off humidifier + setPlugState(humidifierPlug, false); // Turn off humidifier } else if (humidity < desiredHumidity - HUMIDITY_HYSTERESIS) { // Humidity too low Serial.printf("Humidity too low in %s mode! Turning on humidifier...\n", mode); // - setPlugState(humidifierPlugAlias, true); // Turn on humidifier + setPlugState(humidifierPlug, true); // Turn on humidifier } else { // Humidity within range - setPlugState(humidifierPlugAlias, false); // Turn off humidifier to save energy + setPlugState(humidifierPlug, false); // Turn off humidifier to save energy } } @@ -314,7 +315,7 @@ void showStart() { int16_t y = (SCREEN_HEIGHT - text_h) / 2; display.setCursor(x, y); - display.print(text); + display.print(STARTUP_TEXT); display.display(); delay(SCREEN_STARTUP_DISPLAY_TIME); display.clearDisplay(); @@ -531,4 +532,4 @@ void loop() { } } // ============================================================================ -//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber +//vim: filetype=arduino:shiftwidth=2:softtabstop=2:expandtab:nowrap:cursorline:cursorcolumn:number:relativenumber \ No newline at end of file