#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Arduino.h>

// Constants for the pins
const int motorPin = 4;    // PWM pin to control motor speed
const int buzzerPin = 18;   // Buzzer pin
const int potPin = 34;      // Potentiometer (throttle) pin
const int yellowPin = 25;   // Indicator pin (yellow)
const int orangePin = 33;   // Indicator pin (orange)
const int redPin = 32;      // Indicator pin (red)

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

// Speed range constants
const int maxSpeed = 360; // Maximum speed in km/h
const int minSpeed = 0;   // Minimum speed in km/h

/**
 * Initializes the OLED display
 */
void initializeDisplay() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Loop forever if OLED initialization fails
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Bike Speed Controller");
  display.display();
  delay(2000);
}

/**
 * Updates the OLED display with the current speed
 * @param speed The current speed in km/h
 */
void updateDisplay(int speed) {
  display.clearDisplay();
  display.setCursor(0, 0);
  display.print("Bike Speed Controller");
  display.setCursor(0, 30);
  display.print("Speed: ");
  display.print(speed);
  display.print(" KMs/Hr");
  display.display();
}

void setup() {
  // Initialize serial communication
  Serial.begin(115200);
  Serial.println("Hello, ESP32!");

  // Initialize motor control and buzzer pins
  pinMode(motorPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  pinMode(orangePin, OUTPUT);
  pinMode(redPin, OUTPUT);
  
  // Initialize OLED display
  initializeDisplay();
}

void loop() {
  // Read the potentiometer value
  int potValue = analogRead(potPin);
  
  // Map the potentiometer value (0-4095) to the speed range (0-360)
  int speed = map(potValue, 0, 4095, minSpeed, maxSpeed);
  
  // Control the motor speed with PWM
  int pwmValue = map(speed, 0, maxSpeed, 0, 255); // PWM range (0-255)
  analogWrite(motorPin, pwmValue);

  // Print speed to Serial Monitor
  Serial.print("Speed: ");
  Serial.print(speed);
  Serial.println(" KMs/Hr");

  // Update the OLED display with the current speed
  updateDisplay(speed);

  // Control indicators based on speed
  if (speed > 0 && speed <= 120) {
    digitalWrite(yellowPin, HIGH);
    digitalWrite(orangePin, LOW);
    digitalWrite(redPin, LOW);
  } else if (speed > 120 && speed <= 240) {
    digitalWrite(yellowPin, LOW);
    digitalWrite(orangePin, HIGH);
    digitalWrite(redPin, LOW);
  } else if (speed > 240) {
    digitalWrite(yellowPin, LOW);
    digitalWrite(orangePin, LOW);
    digitalWrite(redPin, HIGH);
    digitalWrite(buzzerPin, HIGH); // Activate buzzer
  } else {
    digitalWrite(yellowPin, LOW);
    digitalWrite(orangePin, LOW);
    digitalWrite(redPin, LOW);
  }

  delay(100); // Update speed every 100 ms
}