Untitled

 avatar
unknown
plain_text
a month ago
8.7 kB
6
Indexable
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// -------------------- PINS --------------------
const int TEMP_PIN = 4;       // DS18B20 data pin
const int MQ5_PIN = A0;       // MQ-5 analog output
const int MOISTURE_PIN = A1;  // Capacitive moisture sensor analog output

const int FAN_PIN = 5;        // PWM pin -> fan MOSFET
const int PUMP_PIN = 6;       // pump MOSFET (ON/OFF only)
const int BUZZER_PIN = 7;     // Active buzzer

// -------------------- LCD --------------------
LiquidCrystal_I2C lcd(0x27, 20, 4);

// -------------------- DS18B20 --------------------
OneWire oneWire(TEMP_PIN);
DallasTemperature tempSensor(&oneWire);

// -------------------- STARTUP --------------------
const unsigned long STARTUP_DELAY = 20000UL;   // 20 seconds
unsigned long startupTime = 0;

// -------------------- TEMPERATURE SETTINGS --------------------
const float FAN_ON_TEMP = 40.0;
const float FAN_OFF_TEMP = 37.0;
const float FAN_FULL_TEMP = 45.0;

const int FAN_MIN_PWM = 77;    // about 30%
const int FAN_MAX_PWM = 255;   // 100%

const int PUMP_PWM = 150;   // 0 to 255

const float TEMP_OFFSET = 0.0;   // <-- REPLACE AFTER TEMP CALIBRATION

// -------------------- MOISTURE SETTINGS --------------------
const int MOISTURE_RAW_DRY = 900;   // <-- REPLACE AFTER MOISTURE CALIBRATION
const int MOISTURE_RAW_WET = 300;   // <-- REPLACE AFTER MOISTURE CALIBRATION

const float MOISTURE_ON_PERCENT = 45.0;   // dry threshold
const float MOISTURE_OFF_PERCENT = 55.0;  // wet threshold

const unsigned long PUMP_RUN_TIME = 3000UL;    // 3 seconds ON
const unsigned long PUMP_PAUSE_TIME = 7000UL;  // 7 seconds OFF

// -------------------- GAS SETTINGS --------------------
const int MQ_BASELINE = 350;   // <-- REPLACE AFTER MQ-5 CALIBRATION

const int GAS_ON_THRESHOLD  = (int)(MQ_BASELINE * 1.40);
const int GAS_OFF_THRESHOLD = (int)(MQ_BASELINE * 1.00);

// -------------------- BUZZER PATTERN --------------------
// 150 ms ON, 150 ms OFF, 150 ms ON, 700 ms OFF
const unsigned long BUZZER_TOTAL = 1150UL;

// -------------------- TIMING --------------------
const unsigned long TEMP_INTERVAL = 1000UL;
const unsigned long MOISTURE_INTERVAL = 2000UL;
const unsigned long GAS_INTERVAL = 1000UL;
const unsigned long LCD_INTERVAL = 1000UL;

// -------------------- VARIABLES --------------------
unsigned long lastTempRead = 0;
unsigned long lastMoistureRead = 0;
unsigned long lastGasRead = 0;
unsigned long lastLcdUpdate = 0;

float tempC = 0.0;
bool tempValid = false;

int moistureRaw = 0;
float moisturePercent = 0.0;
bool moistureValid = false;

int gasRaw = 0;

bool fanState = false;
int fanPwm = 0;

bool moistureDemand = false;
bool pumpState = false;
unsigned long pumpStartTime = 0;
unsigned long nextPumpTime = 0;

bool gasAlert = false;

// -------------------- HELPERS --------------------
float mapFloat(float x, float in_min, float in_max, float out_min, float out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

float constrainFloat(float x, float minVal, float maxVal) {
  if (x < minVal) return minVal;
  if (x > maxVal) return maxVal;
  return x;
}

void printLine(int row, String text) {
  while (text.length() < 20) text += " ";
  lcd.setCursor(0, row);
  lcd.print(text.substring(0, 20));
}

void turnEverythingOff() {
  analogWrite(FAN_PIN, 0);
  digitalWrite(PUMP_PIN, 0);
  digitalWrite(BUZZER_PIN, LOW);

  fanPwm = 0;
  pumpState = false;
}

void readTemperature() {
  tempSensor.requestTemperatures();
  float rawTemp = tempSensor.getTempCByIndex(0);

  if (rawTemp > -50 && rawTemp < 125) {
    tempC = rawTemp + TEMP_OFFSET;
    tempValid = true;
  } else {
    tempValid = false;
  }
}

void readMoisture() {
  moistureRaw = analogRead(MOISTURE_PIN);

  moisturePercent = mapFloat(
    moistureRaw,
    MOISTURE_RAW_DRY,
    MOISTURE_RAW_WET,
    0.0,
    100.0
  );

  moisturePercent = constrainFloat(moisturePercent, 0.0, 100.0);
  moistureValid = true;
}

void readGas() {
  gasRaw = analogRead(MQ5_PIN);
}

void controlFan() {
  if (!tempValid) {
    fanState = false;
    fanPwm = 0;
    analogWrite(FAN_PIN, 0);
    return;
  }

  if (tempC >= FAN_ON_TEMP) {
    fanState = true;
  } else if (tempC <= FAN_OFF_TEMP) {
    fanState = false;
  }

  if (!fanState) {
    fanPwm = 0;
  } else {
    if (tempC < FAN_ON_TEMP) {
      fanPwm = FAN_MIN_PWM;
    } else if (tempC >= FAN_FULL_TEMP) {
      fanPwm = FAN_MAX_PWM;
    } else {
      fanPwm = (int)mapFloat(tempC, FAN_ON_TEMP, FAN_FULL_TEMP, FAN_MIN_PWM, FAN_MAX_PWM);
    }
  }

  analogWrite(FAN_PIN, fanPwm);
}

void controlPump(unsigned long now) {
  // Hysteresis decision
  if (moisturePercent < MOISTURE_ON_PERCENT) {
    moistureDemand = true;
  } else if (moisturePercent >= MOISTURE_OFF_PERCENT) {
    moistureDemand = false;
  }

  // If no watering needed, keep pump OFF
  if (!moistureDemand) {
    pumpState = false;
    digitalWrite(PUMP_PIN, 0);
    return;
  }

  // If pump is currently ON, stop after 3 seconds
  if (pumpState) {
    if (now - pumpStartTime >= PUMP_RUN_TIME) {
      pumpState = false;
      digitalWrite(PUMP_PIN, 0);
      nextPumpTime = now + PUMP_PAUSE_TIME;
    }
    return;
  }

  // If pump is OFF but still dry, wait 7 seconds then ON again
  if (now >= nextPumpTime) {
    pumpState = true;
    pumpStartTime = now;
    analogWrite(PUMP_PIN, PUMP_PWM);
  }
}

void controlGas() {
  if (gasRaw >= GAS_ON_THRESHOLD) {
    gasAlert = true;
  } else if (gasRaw <= GAS_OFF_THRESHOLD) {
    gasAlert = false;
  }
}

void controlBuzzer(unsigned long now) {
  if (!gasAlert) {
    digitalWrite(BUZZER_PIN, LOW);
    return;
  }

  unsigned long t = now % BUZZER_TOTAL;

  if ((t < 150) || (t >= 300 && t < 450)) {
    digitalWrite(BUZZER_PIN, HIGH);
  } else {
    digitalWrite(BUZZER_PIN, LOW);
  }
}

String getStatus() {
  bool hot = fanState;
  bool dry = moistureDemand;
  bool gas = gasAlert;

  if (!hot && !dry && !gas) return "NORMAL";
  if (!hot && !dry && gas) return "GAS ALERT";

  String s = "";

  if (hot) s += "HOT";

  if (dry) {
    if (s.length() > 0) s += "+";
    s += "DRY";
  }

  if (gas) {
    if (s.length() > 0) s += "+";
    s += "GAS";
  }

  return s;
}

void showStartupScreen(unsigned long now) {
  unsigned long elapsed = now - startupTime;
  unsigned long remaining = (STARTUP_DELAY - elapsed + 999UL) / 1000UL;

  printLine(0, "Smart Compost System");
  printLine(1, "Initializing...");
  printLine(2, "MQ Warmup: " + String(remaining) + "s");
  printLine(3, "Please wait...");
}

void showMainScreen() {
  int fanPercent = map(fanPwm, 0, 255, 0, 100);

  String line1;
  if (tempValid) {
    line1 = "Temp:" + String(tempC, 1) + "C Fan:" + String(fanPercent) + "%";
  } else {
    line1 = "Temp:ERR Fan:" + String(fanPercent) + "%";
  }

  String line2;
  if (moistureValid) {
    line2 = "Moist:" + String((int)moisturePercent) + "% Pump:" + (pumpState ? "ON" : "OFF");
  } else {
    line2 = "Moist:--% Pump:OFF";
  }

  String line3 = "Gas:" + String(gasRaw) + " Buzzer:" + (gasAlert ? "ON" : "OFF");
  String line4 = "Status: " + getStatus();

  printLine(0, line1);
  printLine(1, line2);
  printLine(2, line3);
  printLine(3, line4);
}

// -------------------- SETUP --------------------
void setup() {
  pinMode(FAN_PIN, OUTPUT);
  pinMode(PUMP_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  analogWrite(FAN_PIN, 0);
  digitalWrite(PUMP_PIN, LOW);
  digitalWrite(BUZZER_PIN, LOW);

  lcd.init();
  lcd.backlight();

  tempSensor.begin();

  startupTime = millis();
}

// -------------------- LOOP --------------------
void loop() {
  unsigned long now = millis();

  // 20-second startup lockout
  if (now - startupTime < STARTUP_DELAY) {
    turnEverythingOff();

    if (now - lastLcdUpdate >= 250) {
      lastLcdUpdate = now;
      showStartupScreen(now);
    }
    return;
  }

  if (now - lastTempRead >= TEMP_INTERVAL) {
    lastTempRead = now;
    readTemperature();
  }

  if (now - lastMoistureRead >= MOISTURE_INTERVAL) {
    lastMoistureRead = now;
    readMoisture();
  }

  if (now - lastGasRead >= GAS_INTERVAL) {
    lastGasRead = now;
    readGas();
  }

  controlFan();
  controlPump(now);
  controlGas();
  controlBuzzer(now);

  if (now - lastLcdUpdate >= LCD_INTERVAL) {
    lastLcdUpdate = now;
    showMainScreen();
  }
}
Editor is loading...
Leave a Comment