// === Roof Controller with Rain Sensor and Debug Logging === #define DEBUG true // Set to false to disable debug messages // Relay output pins #define RELAY_STOP 4 #define RELAY_SENSOR 5 #define RELAY_CLOSE 6 #define RELAY_OPEN 7 // Limit switch input pins #define ROOF_OPENED 11 #define ROOF_CLOSED 12 // Rain sensor analog pin #define RAIN_SENSOR_PIN A0 const int RAIN_THRESHOLD = 700; // Adjust for your sensor // State tracking String serialin; String str; unsigned long end_time; bool roofLost = false; bool autoClosed = false; void setup() { Serial.begin(9600); // Set relay pins as outputs pinMode(RELAY_OPEN, OUTPUT); pinMode(RELAY_CLOSE, OUTPUT); pinMode(RELAY_STOP, OUTPUT); pinMode(RELAY_SENSOR, OUTPUT); // Set limit switch pins as inputs with pull-ups pinMode(ROOF_CLOSED, INPUT_PULLUP); pinMode(ROOF_OPENED, INPUT_PULLUP); // Initialize relays to OFF deactivateAllRelays(); // Initialize lost roof timer end_time = millis() + 60000; // Startup message Serial.write("RRCI#"); } void loop() { updateRoofTimer(); handleRainAutoClose(); handleSerialInput(); checkLimitSwitches(); } // === Helper Functions === void deactivateAllRelays() { digitalWrite(RELAY_OPEN, LOW); digitalWrite(RELAY_CLOSE, LOW); digitalWrite(RELAY_STOP, LOW); digitalWrite(RELAY_SENSOR, LOW); } bool isRaining() { int rainVal = analogRead(RAIN_SENSOR_PIN); if (DEBUG) { Serial.print("Rain Sensor Value: "); Serial.println(rainVal); } return rainVal <= RAIN_THRESHOLD; } bool isRoofOpen() { return digitalRead(ROOF_OPENED) == LOW; } bool isRoofClosed() { return digitalRead(ROOF_CLOSED) == LOW; } void activateSensor() { digitalWrite(RELAY_SENSOR, HIGH); delay(1000); // Allow sensor to warm up } void deactivateSensor() { digitalWrite(RELAY_SENSOR, LOW); } void updateRoofTimer() { if (millis() >= end_time) { if (!isRoofOpen() && !isRoofClosed()) { roofLost = true; } } if (isRoofOpen() || isRoofClosed()) { roofLost = false; end_time = millis() + 60000; } } void handleRainAutoClose() { if (isRaining()) { if (isRoofOpen() && !autoClosed) { if (DEBUG) Serial.println("Rain detected! Auto-closing roof..."); activateSensor(); digitalWrite(RELAY_CLOSE, HIGH); delay(1000); // Allow close action to begin deactivateSensor(); autoClosed = true; } } else if (isRoofClosed()) { autoClosed = false; if (DEBUG) Serial.println("Roof is closed and dry — autoClosed reset."); } } void handleSerialInput() { while (Serial.available() > 0) { serialin = Serial.readStringUntil('#'); if (serialin == "on") { digitalWrite(RELAY_SENSOR, HIGH); if (DEBUG) Serial.println("Command: SENSOR ON"); } else if (serialin == "off") { digitalWrite(RELAY_SENSOR, LOW); if (DEBUG) Serial.println("Command: SENSOR OFF"); } else if (serialin == "x") { digitalWrite(RELAY_OPEN, LOW); if (DEBUG) Serial.println("Command: STOP OPEN RELAY"); } else if (serialin == "y") { digitalWrite(RELAY_CLOSE, LOW); if (DEBUG) Serial.println("Command: STOP CLOSE RELAY"); } else if (serialin == "open") { if (isRaining()) { Serial.println("RainDetected#"); if (DEBUG) Serial.println("Command: OPEN blocked due to rain"); } else { if (DEBUG) Serial.println("Command: OPENING roof"); activateSensor(); digitalWrite(RELAY_OPEN, HIGH); deactivateSensor(); } } else if (serialin == "close") { if (DEBUG) Serial.println("Command: CLOSING roof"); activateSensor(); digitalWrite(RELAY_CLOSE, HIGH); deactivateSensor(); } else if (serialin == "Parkstatus") { Serial.println("0#"); if (DEBUG) Serial.println("Command: PARKSTATUS"); } else if (serialin == "get") { handleGetStatus(); } else if (serialin == "Status") { Serial.println("RoofOpen#"); if (DEBUG) Serial.println("Command: STATUS"); } serialin = ""; // Clear after handling } } void checkLimitSwitches() { if (isRoofClosed() && digitalRead(RELAY_CLOSE) == HIGH) { digitalWrite(RELAY_CLOSE, LOW); if (DEBUG) Serial.println("Limit: Roof CLOSED — Stopping close relay"); } if (isRoofOpen() && digitalRead(RELAY_OPEN) == HIGH) { digitalWrite(RELAY_OPEN, LOW); if (DEBUG) Serial.println("Limit: Roof OPENED — Stopping open relay"); } } void handleGetStatus() { if (DEBUG) Serial.println("Command: GET status"); if (isRoofOpen()) { str += "opened,"; if (DEBUG) Serial.println("Roof Status: OPENED"); } else if (isRoofClosed()) { str += "closed,"; if (DEBUG) Serial.println("Roof Status: CLOSED"); } else { str += "unknown,"; if (DEBUG) Serial.println("Roof Status: UNKNOWN"); } str += isRaining() ? "rain," : "dry,"; if (!isRoofClosed() && isRoofOpen() && !roofLost) { str += "not_moving_o#"; end_time = millis() + 60000; } else if (isRoofClosed() && !isRoofOpen() && !roofLost) { str += "not_moving_c#"; end_time = millis() + 60000; } else if (!isRoofClosed() && !isRoofOpen() && !roofLost) { str += "moving#"; } else if (!isRoofClosed() && !isRoofOpen() && roofLost) { str += "unknown#"; } if (str.endsWith(",")) { str += "unknown#"; } Serial.println(str); str = ""; // Reset after sending }