// Smart Plant Watering - Complete Version for Arduino Nano with OLED
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Display settings - Use 32px height to save memory
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Pin definitions
#define DHT_PIN 2
#define DHT_TYPE DHT22
#define SOIL_PIN A2
#define WATER_PIN A3
#define PUMP_PIN 7
#define BUZZ_PIN 8
DHT dht(DHT_PIN, DHT_TYPE);
// Thresholds - adjust these!
const int DRY_THRESH = 300;
const int WATER_THRESH = 100;
const unsigned long PUMP_TIME = 3000;
const unsigned long WAIT_TIME = 300000; // 5 min
// Variables
unsigned long lastWater = 0;
unsigned long lastRead = 0;
unsigned long lastDisplay = 0;
bool pumpOn = false;
bool displayAvailable = false;
float temp, humid;
int soil, water, soilPct;
void setup() {
Serial.begin(9600);
dht.begin();
pinMode(PUMP_PIN, OUTPUT);
pinMode(BUZZ_PIN, OUTPUT);
digitalWrite(PUMP_PIN, HIGH); // Set HIGH for active-low relay (OFF position)
// Try to initialize display
if(display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
displayAvailable = true;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println(F("Plant Watering"));
display.println(F("System Ready"));
display.println(F("Starting..."));
display.display();
Serial.println("Display initialized");
} else {
displayAvailable = false;
Serial.println("Display failed - continuing without");
}
Serial.println("Plant Watering Ready");
Serial.println("Commands: t=test, c=calibrate, s=status");
Serial.println("Format: Moisture%,Temp,Humidity,Water,Pump,Threshold");
tone(BUZZ_PIN, 1000, 200);
delay(300);
tone(BUZZ_PIN, 1500, 200);
delay(2000); // Give DHT time to stabilize
}
void loop() {
// Read sensors every 2 seconds
if (millis() - lastRead >= 2000) {
readSensors();
lastRead = millis();
}
// Handle serial commands
if (Serial.available()) {
char cmd = Serial.read();
if (cmd == 't') testPump();
if (cmd == 'c') calibrate();
if (cmd == 's') status();
}
// Check watering
checkWater();
// Update display every 3 seconds
if (displayAvailable && (millis() - lastDisplay >= 3000)) {
updateDisplay();
lastDisplay = millis();
}
// Send plotter data every 5 seconds
static unsigned long lastPlot = 0;
if (millis() - lastPlot >= 5000) {
sendData();
lastPlot = millis();
}
delay(100);
}
void readSensors() {
soil = analogRead(SOIL_PIN);
water = analogRead(WATER_PIN);
temp = dht.readTemperature();
humid = dht.readHumidity();
soilPct = map(soil, 1023, 0, 0, 100);
soilPct = constrain(soilPct, 0, 100);
if (isnan(temp)) temp = 0;
if (isnan(humid)) humid = 0;
}
void updateDisplay() {
if (!displayAvailable) return;
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
// Line 1: Soil moisture (larger text)
display.setTextSize(2);
display.print(F("Soil:"));
display.print(soilPct);
display.println(F("%"));
// Line 2: Temperature and humidity
display.setTextSize(1);
display.print(F("T:"));
display.print((int)temp);
display.print(F("C H:"));
display.print((int)humid);
display.print(F("%"));
// Line 3: Status indicator
if (pumpOn) {
display.print(F(" PUMP"));
} else if (water <= WATER_THRESH) {
display.print(F(" LOW H2O"));
} else {
display.print(F(" OK"));
}
display.display();
}
void checkWater() {
bool dry = (soil < DRY_THRESH);
bool timeOK = (millis() - lastWater > WAIT_TIME);
bool hasWater = (water > WATER_THRESH);
// Start watering
if (dry && timeOK && hasWater && !pumpOn) {
Serial.print("WATERING - Soil was ");
Serial.print(soilPct);
Serial.println("%");
digitalWrite(PUMP_PIN, LOW); // Changed to LOW for active-low relay
pumpOn = true;
lastWater = millis();
tone(BUZZ_PIN, 800, 200);
// Update display immediately
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println(F("WATERING"));
display.setTextSize(1);
display.print(F("Soil was: "));
display.print(soilPct);
display.println(F("%"));
display.display();
}
}
// Stop watering
if (pumpOn && (millis() - lastWater > PUMP_TIME)) {
Serial.println("Watering complete");
digitalWrite(PUMP_PIN, HIGH); // Changed to HIGH for active-low relay (OFF)
pumpOn = false;
tone(BUZZ_PIN, 1200, 200);
}
// Low water alert
if (!hasWater && (millis() % 15000 < 100)) {
Serial.println("LOW WATER!");
tone(BUZZ_PIN, 2000, 100);
// Flash low water warning on display
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println(F("LOW"));
display.println(F("WATER!"));
display.display();
delay(1000);
}
}
}
void sendData() {
// Serial Plotter format
Serial.print(soilPct);
Serial.print(",");
Serial.print(temp);
Serial.print(",");
Serial.print(humid);
Serial.print(",");
Serial.print(water);
Serial.print(",");
Serial.print(pumpOn ? 100 : 0);
Serial.print(",");
Serial.println(30); // Reference line
}
void testPump() {
if (water <= WATER_THRESH) {
Serial.println("No water for test");
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.println(F("Test Failed:"));
display.println(F("No Water"));
display.display();
delay(2000);
}
return;
}
Serial.println("Testing pump...");
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(2);
display.println(F("TESTING"));
display.setTextSize(1);
display.println(F("Pump running..."));
display.display();
}
digitalWrite(PUMP_PIN, LOW); // Turn ON pump (LOW for active-low relay)
delay(2000);
digitalWrite(PUMP_PIN, HIGH); // Turn OFF pump (HIGH for active-low relay)
Serial.println("Test done");
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.println(F("Test Complete"));
display.display();
delay(1000);
}
}
void calibrate() {
Serial.println("Calibrating...");
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.println(F("Calibrating..."));
display.println(F("Please wait"));
display.display();
}
int s = 0, w = 0;
for (int i = 0; i < 5; i++) {
s += analogRead(SOIL_PIN);
w += analogRead(WATER_PIN);
delay(200);
}
Serial.print("Soil avg: ");
Serial.print(s/5);
Serial.print(" Water avg: ");
Serial.println(w/5);
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.println(F("Calibration:"));
display.print(F("Soil: "));
display.println(s/5);
display.print(F("Water: "));
display.println(w/5);
display.display();
delay(3000);
}
}
void status() {
readSensors();
Serial.print("Soil: ");
Serial.print(soilPct);
Serial.print("% Temp: ");
Serial.print(temp);
Serial.print("C Humidity: ");
Serial.print(humid);
Serial.print("% Water: ");
Serial.print(water);
Serial.print(" Pump: ");
Serial.println(pumpOn ? "ON" : "OFF");
if (displayAvailable) {
display.clearDisplay();
display.setCursor(0,0);
display.setTextSize(1);
display.println(F("=== STATUS ==="));
display.print(F("Soil: "));
display.print(soilPct);
display.println(F("%"));
display.print(F("Temp: "));
display.print((int)temp);
display.println(F("C"));
display.print(F("Pump: "));
display.println(pumpOn ? F("ON") : F("OFF"));
display.display();
delay(3000);
}
}
Comments2
error
/home/user/.var/app/cc.arduino.IDE2/cache/ccmLN6Y9.ltrans0.ltrans.o: In function `main':
/home/user/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino/main.cpp:43: undefined reference to `setup'
/home/user/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino/main.cpp:46: undefined reference to `loop'
collect2: error: ld returned 1 exit status
exit status 1
Compilation error: exit status 1
error
/home/user/.var/app/cc.arduino.IDE2/cache/ccmLN6Y9.ltrans0.ltrans.o: In function `main':
/home/user/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino/main.cpp:43: undefined reference to `setup'
/home/user/.arduino15/packages/arduino/hardware/avr/1.8.6/cores/arduino/main.cpp:46: undefined reference to `loop'
collect2: error: ld returned 1 exit status
exit status 1
Compilation error: exit status 1