/// @file Deskfan.ino
/// @brief Arduino script to controll a DIY fan for a desk
/// @author Kilian Klepper
/// @date 09/05 , 2024

// Library for DS18B20 temperature sensor
#include <OneWire.h>
#include <DallasTemperature.h>

// Library for OLED Display
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// Display defines
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C

// DS18B20 temperature sensor pin
#define ONE_WIRE_BUS D10

// Setup display instance
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Boost-Converter voltage input
const int analogPin = A3;
int analogValue = 0;
float voltageBoostconverter = 0.0;
// State of rocket switch
bool fanState = false;
int fanPowerPercent = 0;
// Temperature value
float tempC = 0.0;

// Here you can define your voltagedivider from the boostconverter output
const float referenceVoltage = 3.3;
const float R2 = 20000.0;  // 20k ohm
const float R3 = 3300.0;   // 3.3k ohm

// type in your max and minimum voltage
const float Vmax = 22;
const float Vmin = 4;

// get Temperature value
float getTemperature() {
  sensors.requestTemperatures();
  return sensors.getTempCByIndex(0);
}

// get Volage value of boostconverter
float getBoostVoltag(float lastValue) {
  // Read the analog input (0 - 4095)
  analogValue = analogRead(analogPin);     

  // Convert the analog reading to a voltage (0 - 3.3V)
  float vIn = analogValue * (referenceVoltage / 4095.0);  

  // Calculate the input voltage using the voltage divider formula
  // use the two const values to give it a litte Low-pass filter
  return 0.4*(vIn * ((R2 + R3) / R3))+ 0.6 * lastValue;
}

// calculate the fan speed in %
int mapFanPower(float x, float in_min, float in_max, float out_min, float out_max) {
  int result = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  if(result < out_min) result = out_min;
  if(result > out_max) result = out_max;
  return result;
}

void serialMonitor() {
  if(fanState) Serial.print("on  - ");
  else Serial.print("off - ");
  Serial.print(voltageBoostconverter);
  Serial.print(" V - ");
  Serial.print(fanPowerPercent);
  Serial.print("% - ");
  Serial.print(tempC);
  Serial.println("°C");
}

void setup() {
  // set ADC resolution to 12-bit
  analogReadResolution(12);

  // start the temp sensor
  sensors.begin();

  Serial.begin(115200);

  // start the display
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
  display.clearDisplay();
  display.display();
  display.setTextSize(2);
  display.setTextColor(SSD1306_WHITE);
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Desktop Fan");
  display.display();
  
  delay(100);
}

void loop() {
  

  // Update all Inputs
  tempC = getTemperature();
  voltageBoostconverter = getBoostVoltag(voltageBoostconverter);
  fanState = (voltageBoostconverter > 4)? true : false;
  fanPowerPercent = mapFanPower(voltageBoostconverter, Vmin, Vmax, 0.0, 100.0);

  // display all inputs
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(1, 1);
  display.println("Temperatur:");
  display.setCursor(79, 1);
  if(fanState) display.println("ON: ");
  else display.println("OFF: ");
  display.setTextSize(2);
  display.setCursor(1, 10);
  display.print(tempC,1);
  display.print("C");
  display.setCursor(79, 10);
  display.print(fanPowerPercent);
  display.print("%");
  display.display();

  // wait for a little
  delay(100);
}


