//
//    FILE: PID_simulated_heater_pot.ino
//  AUTHOR: drf5n  (based on basic example)
// PURPOSE: demo
//
//  This simulates a 20W heater block driven by the PID
//  Vary the setpoint with the Pot, and watch the heater drive the temperature up
//
//  Code at https://wokwi.com/projects/357374218559137793
//
//  Based on
//  Wokwi https://wokwi.com/projects/356437164264235009
//
//  https://github.com/RobTillaart/PID_RT/issues/5
//

#include "PID_RT.h" // https://github.com/RobTillaart/PID_RT

PID_RT PID;  // https://github.com/RobTillaart/PID_RT

const int PWM_PIN = 3;  // UNO PWM pin
const int INPUT_PIN = -1; // Analog pin for Input (set <0 for simulation)
const int SETPOINT_PIN = A1;   // Analog pin for Setpoint Potentiometer
const int SETPOINT_INDICATOR = 6; // PWM pin for indicating setpoint
const int INPUT_INDICATOR = 5; // PWM pin for indicating Input

int op = 0;
float input = 0;


void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);

  if (SETPOINT_INDICATOR >= 0) pinMode(SETPOINT_INDICATOR, OUTPUT);
  if (INPUT_INDICATOR >= 0) pinMode(INPUT_INDICATOR, OUTPUT);
  PID.setPoint(125);
  PID.setOutputRange(0, 255);  // PWM range
  PID.setInterval(50);
  PID.setK(2, 5, 1);
  PID.start();
  Serial.println("Setpoint Input Output");
  op = analogRead(A0);
}


void loop()
{
  float heaterWatts = ((int)op) * 20.0 / 255; // 20W heater
  if (INPUT_PIN > 0 ) {
    input = analogRead(INPUT_PIN);
  } else {
    float blockTemp = simPlant(heaterWatts); // simulate heating
    input = blockTemp;   // read input from simulated heater block
  }

  if (PID.compute(input))
  {
    op = PID.getOutput();
    analogWrite(PWM_PIN, op);

    //  Serial.print(PID.getInput());
    //  Serial.print('\t');
    //  Serial.println(op);
    PID.setPoint(analogRead(SETPOINT_PIN) / 4); // Read setpoint from potentiometer
    if (INPUT_INDICATOR >= 0) analogWrite(INPUT_INDICATOR, input);
    if (SETPOINT_INDICATOR >= 0) analogWrite(SETPOINT_INDICATOR, PID.getSetPoint());
  }
  report();
}


void report(void) {
  static uint32_t last = 0;
  const int interval = 1000;
  if (millis() - last > interval) {
    last += interval;
    //    Serial.print(millis()/1000.0);
    Serial.print("SP:");
    Serial.print(PID.getSetPoint());
    Serial.print(" PV:");
    Serial.print(input);
    Serial.print(" CV:");
    Serial.println(op);
  }
}

float simPlant(float Q) { // heat input in W (or J/s)
  // simulate a 1x1x2cm aluminum block with a heater and passive ambient cooling
  float C = 237; // W/mK thermal conduction coefficient for Al
  float h = 15 ; // W/m2K thermal convection coefficient for Al passive
  float Cps = 0.89; // J/g°C
  float area = 1e-4; // m2 area for convection
  float mass = 10 ; // g
  float Tamb = 25; // °C
  static float T = Tamb; // °C
  static uint32_t last = 0;
  uint32_t interval = 100; // ms

  if (millis() - last >= interval) {
    last += interval;
    float Qconv =  (T - Tamb) * area * h;
    T = T + (Q - Qconv) * interval / 1000 / mass / Cps ;
  }

  return T;
}


// -- END OF FILE --
255° Setpoint 0°