#include <Wire.h>
#include <MPU6050.h>
#include <DHT.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Encoder.h>
// OLED display settings
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// DHT22 Sensor pin connections
#define DHT_PIN 14
#define DHTTYPE DHT22
DHT dht(DHT_PIN, DHTTYPE);
// MPU6050 Sensor
MPU6050 mpu;
// Relay module pin connections
#define RELAY_PIN 4
// Rotary Encoder pin connections
#define ENCODER_CLK_PIN 32
#define ENCODER_DT_PIN 33
#define ENCODER_SW_PIN 34
Encoder myEnc(ENCODER_CLK_PIN, ENCODER_DT_PIN);
// LED and Pushbutton connections
#define LED_PIN 18
#define BUTTON_PIN 19
volatile long lastPosition = -999;
volatile long encoderValue = 0;
volatile unsigned long lastPulseTime = 0;
volatile unsigned long pulseInterval = 0;
volatile float rpm = 0;
// Function to handle rotary encoder
void IRAM_ATTR handleEncoder() {
long newPosition = myEnc.read();
unsigned long currentTime = millis();
if (newPosition != lastPosition) {
lastPosition = newPosition;
encoderValue = newPosition;
pulseInterval = currentTime - lastPulseTime;
lastPulseTime = currentTime;
// Calculate RPM
if (pulseInterval > 0) {
rpm = (1000.0 / pulseInterval) * 60.0; // Convert to RPM
}
}
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22); // SDA -> GPIO 21, SCL -> GPIO 22
// Initialize DHT sensor
dht.begin();
// Initialize MPU6050 sensor
mpu.initialize();
if (!mpu.testConnection()) {
Serial.println("Failed to connect to MPU6050");
while (1);
} else {
Serial.println("MPU6050 connected.");
}
// Set accelerometer range to ±2g
mpu.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
// Initialize OLED display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
Serial.println("OLED display initialized.");
// Initialize Relay
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
// Initialize LED
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Initialize Pushbutton
pinMode(BUTTON_PIN, INPUT_PULLUP);
// Attach interrupt to the encoder's clock pin
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK_PIN), handleEncoder, CHANGE);
// Set the initial time
struct tm timeinfo;
timeinfo.tm_year = 2024 - 1900; // Year since 1900
timeinfo.tm_mon = 11; // Month (0-11)
timeinfo.tm_mday = 15; // Day of the month
timeinfo.tm_hour = 12; // Hours
timeinfo.tm_min = 0; // Minutes
timeinfo.tm_sec = 0; // Seconds
time_t t = mktime(&timeinfo);
struct timeval now = { .tv_sec = t };
settimeofday(&now, NULL);
Serial.println("Windmill project initialized successfully.");
}
void updateDisplay(float temperature, float humidity, float vibrationMagnitude, float rpm, String dateTime) {
display.clearDisplay();
display.setCursor(0, 0);
display.print("Temp: ");
display.println(temperature);
display.print("Humid: ");
display.println(humidity);
display.print("Vibration: ");
display.println(vibrationMagnitude, 3); // Display vibration magnitude
display.print("RPM: ");
display.println(rpm, 2);
display.print("Time: ");
display.println(dateTime);
display.display();
}
unsigned long previousMillis = 0;
const long interval = 1000;
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// Read temperature and humidity
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
// Read actual vibration data from MPU6050
int16_t ax, ay, az;
mpu.getAcceleration(&ax, &ay, &az);
// Debugging: Print raw accelerometer data
Serial.print("Acc X: ");
Serial.print(ax);
Serial.print(" Acc Y: ");
Serial.print(ay);
Serial.print(" Acc Z: ");
Serial.println(az);
// Convert raw accelerometer data to m/s²
float vibrationX = (ax / 16384.0) * 9.81;
float vibrationY = (ay / 16384.0) * 9.81;
float vibrationZ = (az / 16384.0) * 9.81;
// Debugging: Print converted accelerometer data
Serial.print("Vibration X: ");
Serial.print(vibrationX);
Serial.print(" Vibration Y: ");
Serial.print(vibrationY);
Serial.print(" Vibration Z: ");
Serial.println(vibrationZ);
// Calculate overall vibration magnitude using RMS
float vibrationMagnitude = sqrt(vibrationX * vibrationX + vibrationY * vibrationY + vibrationZ * vibrationZ);
// Debugging: Print calculated vibration magnitude
Serial.print("Vibration Magnitude: ");
Serial.println(vibrationMagnitude, 3);
// Get RPM from the encoder
float currentRPM = rpm;
// Debugging: Print encoder values and calculated RPM
Serial.print("Encoder Value: ");
Serial.println(encoderValue);
Serial.print("RPM: ");
Serial.println(currentRPM, 2);
// Get the current time from internal clock
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
String dateTime = String(timeinfo.tm_hour) + ":" + String(timeinfo.tm_min) + ":" + String(timeinfo.tm_sec);
// Update OLED display
updateDisplay(temperature, humidity, vibrationMagnitude, currentRPM, dateTime);
// Check condition to activate the relay (e.g., high temperature)
if (temperature > 30.0) {
digitalWrite(RELAY_PIN, HIGH); // Turn on the relay
} else {
digitalWrite(RELAY_PIN, LOW); // Turn off the relay
}
// Check pushbutton state to toggle the LED
if (digitalRead(BUTTON_PIN) == LOW) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
// Print readings to Serial Monitor
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.print(" °C, Humidity: ");
Serial.print(humidity);
Serial.print(" %, Vibration: ");
Serial.print(vibrationMagnitude, 3);
Serial.print(" m/s², RPM: ");
Serial.print(currentRPM, 2);
Serial.print(", Time: ");
Serial.println(dateTime);
}
}