Untitled
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