#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

#define i2c_Address 0x3C // OLED Adress.
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1

Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float tempForFanStartup = 28.0; // 82c/175.0F target low temp. below this temperature, the fan will be off
float tempForFanOnFull = 40.0; // 105c/210.0F target High temp. above this temperature, the fan will be on at full power
float tempForIdiotLight = 110.0; //115c

float voltsForFanStartup = 2.0; // Roughly the signal voltage that triggers the mazda module's slowest speed.
// A higher voltage here will effectively increase the fans lowest speed target.

const int fanPwmOutPin = 6; // Arduino forces this pin to 0 or 5 volts.
const int idiotLightPin = 8;
const int tempSensorPin = 7; // Pin to read from the DS1820 temp sensor.
const int temp2SensorPin = 9;
const int LEDpin = 13;
int pwmDuty; // The calculated PWM duty is stored here
float pwmMinStartupDuty; // the starting duty is stored here (mazda module starts fans at about 24 % duty)
float currTemperature; // the temperature in C is stored here
float curr2Temperature; // redundant temp sensor in C stored here
float idiotLight;

OneWire oneWire1 (tempSensorPin);
DallasTemperature sensorClt1(&oneWire1);
OneWire oneWire2 (temp2SensorPin);
DallasTemperature sensorClt2(&oneWire2);

void setup() {
Serial.begin(115200); // set up serial port for 115200 baud (optional)
sensorClt1.begin();
sensorClt2.begin();
sensorClt1.requestTemperatures();
currTemperature = sensorClt1.getTempCByIndex(0);
sensorClt2.requestTemperatures();
curr2Temperature = sensorClt2.getTempCByIndex(0);
//pinMode(tempSensorPin, INPUT);
//pinMode(temp2SensorPin, INPUT);

pinMode(LEDpin, OUTPUT);
analogWrite(fanPwmOutPin, 0); // turn the fan off at start
digitalWrite(idiotLightPin, LOW);
idiotLight = LOW;

//ledcSetup(0, 20000, 8);
//ledcAttachPin(fanPwmOutPin, 0);

//ledcWrite(0, 0);

  if (!display.begin(i2c_Address)) {
    Serial.println(F("SH110X allocation failed"));
    for (;;);
  }

pwmMinStartupDuty = (voltsForFanStartup / 5.0) * 255.0; // convert the Mazda starting voltage to a PWM duty
}

void loop() {
  readAndTranslateTempSensor();
  calculate_and_send_PWM();
  idiotLightAlarm();
  displayOutput();
  LEDblink();
  //print_to_serial_port();
  delay(20);
}

void calculate_and_send_PWM() {
if (currTemperature < tempForFanStartup) { // If the temperature is below the lowest setpoint, turn fan off
analogWrite(fanPwmOutPin, 0); // PWM duty = 0 percent
//ledcWrite(0, 0);
pwmDuty = 0;
return;
}
if (currTemperature > tempForFanOnFull) { // If the temperature is above the highest setpoint, turn fan on full
analogWrite(fanPwmOutPin, 255); // PWM duty = 100 percent
//ledcWrite(0, 255);
pwmDuty = 255;
return;
}

float tempRange = tempForFanOnFull - tempForFanStartup ; // start calculating duty cycle
float pwmRange = 255.0 - pwmMinStartupDuty ;
float pwmDutyPct = (currTemperature - tempForFanStartup) / tempRange ;

pwmDuty = (int) (pwmMinStartupDuty + (pwmDutyPct * pwmRange) +.5); // actual PWM duty is calculated here

if (pwmDuty > 255) { // make sure duty ended up between 255 and 0
pwmDuty = 255;
}
if (pwmDuty < 0) {
pwmDuty = 0;
}

analogWrite(fanPwmOutPin, pwmDuty); // write PWM duty to PWM output pin
//ledcWrite(0, pwmDuty);
}

void readAndTranslateTempSensor() {
//float currTemperature;
sensorClt1.requestTemperatures();
currTemperature = sensorClt1.getTempCByIndex(0);

sensorClt2.requestTemperatures();
curr2Temperature = sensorClt2.getTempCByIndex(0);
}

void displayOutput() {
  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);

// Display temperature on the screen in Celsius with one decimal place
  display.setCursor(10, 10);
  display.print("Temp:");
  display.setCursor(40, 10);
  display.print(currTemperature, 2); // Display one decimal place
  display.setCursor(80, 10);
  display.print("/ ");
  display.print(curr2Temperature, 2);

  display.setCursor(10, 20);
  display.print("PWMd:");
  display.setCursor(40, 20);
  display.print(pwmDuty);

  display.setCursor(10, 30);
  display.print("Lamp:");
  display.setCursor(40, 30);
  display.print(idiotLight, 0);

  // Update the display
  display.display();
}

void idiotLightAlarm() {
  if (currTemperature > tempForIdiotLight) {
    digitalWrite(idiotLightPin, HIGH);
    idiotLight = HIGH;
  }
    else if (currTemperature < tempForIdiotLight) {
    digitalWrite(idiotLightPin, LOW);
    idiotLight = LOW;
  }
}

void LEDblink() {
  digitalWrite(LEDpin, HIGH);
  delay(1000);
  digitalWrite(LEDpin, LOW);
  delay(1000);
}

void print_to_serial_port() {
Serial.print(F("currTemperature C: ")); Serial.print(currTemperature);
Serial.print(F(" pwmDuty: ")); Serial.println(pwmDuty);
}