#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Servo.h>
// --- Pin Definitions ---
#define DHT_PIN 2
#define ONEWIRE_BUS_PIN 3
#define SERVO_PIN 9
#define BTN1_PIN 4 // 60 degrees
#define BTN2_PIN 5 // 90 degrees
#define BTN3_PIN 6 // 180 degrees
#define BTN4_PIN 7 // Toggle Sweep Mode
// --- Component Initializations ---
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
OneWire oneWire(ONEWIRE_BUS_PIN);
DallasTemperature sensors(&oneWire);
Servo myServo;
// --- Timers and State Variables ---
// For passive display
unsigned long previousDisplayMillis = 0;
const long displayInterval = 5000;
int displayState = 0;
// For servo sweep mode
bool isSweeping = false;
unsigned long previousServoMillis = 0;
const int servoInterval = 15; // ms delay between servo steps
int servoPos = 0;
int servoDirection = 1; // 1 for forward, -1 for backward
void setup() {
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("System Ready!");
dht.begin();
sensors.begin();
myServo.attach(SERVO_PIN);
myServo.write(0);
delay(1500);
// Initialize all buttons
pinMode(BTN1_PIN, INPUT_PULLUP);
pinMode(BTN2_PIN, INPUT_PULLUP);
pinMode(BTN3_PIN, INPUT_PULLUP);
pinMode(BTN4_PIN, INPUT_PULLUP);
}
void loop() {
unsigned long currentMillis = millis();
handleButtons(); // Check for any button presses
handleServoSweep(currentMillis); // Handle sweep motion if active
handlePassiveDisplay(currentMillis); // Handle sensor display
}
// --- Main Logic Functions ---
void handleButtons() {
if (digitalRead(BTN1_PIN) == LOW) {
isSweeping = false; // Stop sweeping if active
myServo.write(60); // Directly control the servo
delay(50); // Simple debounce
}
if (digitalRead(BTN2_PIN) == LOW) {
isSweeping = false;
myServo.write(90);
delay(50);
}
if (digitalRead(BTN3_PIN) == LOW) {
isSweeping = false;
myServo.write(180);
delay(50);
}
if (digitalRead(BTN4_PIN) == LOW) {
isSweeping = !isSweeping; // Toggle sweep mode
delay(100); // Simple debounce to prevent rapid toggling
}
}
void handleServoSweep(unsigned long currentMillis) {
if (isSweeping) {
if (currentMillis - previousServoMillis >= servoInterval) {
previousServoMillis = currentMillis;
servoPos = servoPos + servoDirection;
myServo.write(servoPos);
// Reverse direction at the ends
if (servoPos <= 0 || servoPos >= 180) {
servoDirection *= -1; // Flips between 1 and -1
}
}
}
}
void handlePassiveDisplay(unsigned long currentMillis) {
// Check if it's time to switch the display, REGARDLESS of sweep mode
if (currentMillis - previousDisplayMillis >= displayInterval) {
previousDisplayMillis = currentMillis;
displayState = !displayState;
if (displayState == 0) {
displayDHT22();
} else {
displayDS18B20();
}
}
}
// --- Display Functions ---
void displayDHT22() {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT22 Read Err");
return;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Humidity & Temp");
lcd.setCursor(0, 1);
lcd.print("T:");
lcd.print(t, 1);
lcd.print((char)223);
lcd.print("C H:");
lcd.print(h, 1);
lcd.print("%");
}
void displayDS18B20() {
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Probe Temp");
if (tempC == DEVICE_DISCONNECTED_C) {
lcd.setCursor(0,1);
lcd.print("Sensor Error");
return;
}
lcd.setCursor(0, 1);
lcd.print("Temp: ");
lcd.print(tempC, 2);
lcd.print((char)223);
lcd.print("C");
}