#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>  // For making the GET request

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Relay pins
const int line1RelayPin = 18;
const int line2RelayPin = 4;

// Fault check points
const int r1Pin = 12; // Line 1 Resistance Check
const int r2Pin = 26; // Line 2 Resistance Check
const int g1Pin = 25; // Line 1 Ground Check
const int g2Pin = 14; // Line 2 Ground Check
const int v1Pin = 33; // Line 1 Voltage Check
const int v2Pin = 27; // Line 2 Voltage Check

// Latitude and Longitude for each fault point (assumed values)
float latR1 = 19.031124, lonR1 = 72.841415; // Line 1 Resistance Check
float latR2 = 19.031924, lonR2 = 72.859415; // Line 2 Resistance Check
float latG1 = 19.021224, lonG1 = 72.842415; // Line 1 Ground Check
float latG2 = 19.021924, lonG2 = 72.849415; // Line 2 Ground Check
float latV1 = 19.111146, lonV1 = 72.861736; // Line 1 Voltage Check
float latV2 = 19.113646, lonV2 =  72.869736; // Line 2 Voltage Check

// Distance definitions
const int distanceR = 1; // 1 km
const int distanceG = 2; // 2 km
const int distanceV = 3; // 3 km

// Variables to store the last fault details
String lastLineNumber;
int lastDistance = 0;
float lastLat = 0.0, lastLon = 0.0;
int faultFlag = 0;

// WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);
  
  // Initialize the OLED display with error handling
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Ensure I2C address is correct
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  
  // Initialize relay pins as outputs
  pinMode(line1RelayPin, OUTPUT);
  pinMode(line2RelayPin, OUTPUT);

  // Initialize fault check pins as inputs
  pinMode(r1Pin, INPUT_PULLUP); // Pull-up resistor for stable input
  pinMode(r2Pin, INPUT_PULLUP);
  pinMode(g1Pin, INPUT_PULLUP);
  pinMode(g2Pin, INPUT_PULLUP);
  pinMode(v1Pin, INPUT_PULLUP);
  pinMode(v2Pin, INPUT_PULLUP);

  // Initialize WiFi
  connectToWiFi();

  Serial.println("Fault Detection System Initialized");
  delay(1000);
}

void loop() {
  // Read the pin states
  int r1State = digitalRead(r1Pin);
  int g1State = digitalRead(g1Pin);
  int v1State = digitalRead(v1Pin);

  int r2State = digitalRead(r2Pin);
  int g2State = digitalRead(g2Pin);
  int v2State = digitalRead(v2Pin);

  // Reset faultFlag before checking
  faultFlag = 0;

  // Check fault conditions for Line 1
  if (r1State == HIGH) {
    updateFault("1", distanceR, latR1, lonR1, line1RelayPin);
  } else if (g1State == HIGH) {
    updateFault("1", distanceG, latG1, lonG1, line1RelayPin);
  } else if (v1State == HIGH) {
    updateFault("1", distanceV, latV1, lonV1, line1RelayPin);
  }

  // Check fault conditions for Line 2
  if (r2State == HIGH) {
    updateFault("2", distanceR, latR2, lonR2, line2RelayPin);
  } else if (g2State == HIGH) {
    updateFault("2", distanceG, latG2, lonG2, line2RelayPin);
  } else if (v2State == HIGH) {
    updateFault("2", distanceV, latV2, lonV2, line2RelayPin);
  }

  // Print last fault details if faultFlag == 1
  if (faultFlag == 1) {
    printLastFault();
    sendFaultDetailsToAPI(lastLineNumber, lastDistance, lastLat, lastLon); // Send fault details to ThingSpeak
  }

  // Delay before the next check
  delay(1000);
}

// Function to update the last fault details and set the relay HIGH
void updateFault(const String& line, int distance, float lat, float lon, int relayPin) {
  lastLineNumber = line;
  lastDistance = distance;
  lastLat = lat;
  lastLon = lon;
  faultFlag = 1;
  digitalWrite(relayPin, HIGH); // Set relay HIGH for the faulted line
}

// Function to print the last fault details
void printLastFault() {
  // Print fault details to serial monitor
  Serial.println("===== LAST FAULT DETAILS =====");
  Serial.print("Line: "); Serial.println(lastLineNumber);
  Serial.print("Distance: "); Serial.print(lastDistance); Serial.println(" km");
  Serial.print("Latitude: "); Serial.print(lastLat, 4); 
  Serial.print(" | Longitude: "); Serial.println(lastLon, 4);
  Serial.println("================================");

  // Display fault on OLED
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Last Fault at:");
  display.setCursor(0, 10);
  display.print(lastLineNumber);
  display.setCursor(0, 20);
  display.print("Dist: ");
  display.print(lastDistance);
  display.print(" km");
  display.setCursor(0, 30);
  display.print("Lat: ");
  display.print(lastLat, 4);
  display.setCursor(0, 40);
  display.print("Lon: ");
  display.print(lastLon, 4);
  display.display();
}

// Function to connect to WiFi
void connectToWiFi() {
  Serial.println("Connecting to WiFi...");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");
}

// Function to send fault details to ThingSpeak via GET request
void sendFaultDetailsToAPI(const String& line, int distance, float lat, float lon) {
  if (WiFi.status() == WL_CONNECTED) {
    WiFiClient client;
    String url = "https://api.thingspeak.com/update?api_key=K8CH7XH11OFPA1WG";
    url += "&field1=" + line;
    url += "&field2=" + String(distance);
    url += "&field3=" + String(lon, 4);
    url += "&field4=" + String(lat, 4);

    Serial.print("Making GET request: ");
    Serial.println(url);

    if (client.connect("api.thingspeak.com", 80)) {
      client.print(String("GET ") + url + " HTTP/1.1\r\n" +
                   "Host: api.thingspeak.com\r\n" +
                   "Connection: close\r\n\r\n");
      delay(500);

      while (client.available()) {
        String response = client.readString();
        Serial.println(response);
      }
    } else {
      Serial.println("Connection to ThingSpeak failed");
    }
  } else {
    Serial.println("WiFi not connected");
  }
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module