#include <LiquidCrystal_I2C.h>
#include <Servo.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
Servo servoVentFront;
Servo servoVentHigh;
Servo servoVentLow;
Servo servoCirc;
/*
Pins for buttons: A6-A15
Pins for relays: 22-53
Pins for PWM: 2-13
Pins for display: 20 & 21
Pins for sensors: A0-A5
*/
int pinSensorKeyON = 22;
int pinSensorAlternator = 23;
// Temp Sensors
int pinSensorExterior = A0;
int pinSensorInterior = A1;
int pinSensorDischarge = A2;
// Fans & Compressor
int pinRelayServos = 24; // For blower fan & servos
int pinRelayFan = 25; // For blower fan & servos
int pinFanPWM = 2;
int pinRelayCompressor = 26;
int pinRelayCondenserFan = 27;
// Vents & Circulation Servos
int pinServoCirc = 3;
int pinServoVentFront = 4;
int pinServoVentLow = 5;
int pinServoVentHigh = 6;
// Buttons
int pinOffOnBtn = A6;
int pinModeBtn = A7;
int pinCircBtn = A8;
int pinAcBtn = A9;
int pinAutoBtn = A10;
int pinFanDownBtn = A11;
int pinFanUpBtn = A12;
int pinTempDownBtn = A13;
int pinTempUpBtn = A14;
// Button States
int btnOffOn = 0;
int btnAC = 0;
int btnAuto = 0;
int btnCirc = 0;
int btnMode = 0;
int btnTempUp = 0;
int btnTempDown = 0;
int btnFanUp = 0;
int btnFanDown = 0;
// Last Button States
int lastBtnOffOn = 0;
int lastBtnAC = 0;
int lastBtnAuto = 0;
int lastBtnCirc = 0;
int lastBtnMode = 0;
int lastBtnTempUp = 0;
int lastBtnTempDown = 0;
int lastBtnFanUp = 0;
int lastBtnFanDown = 0;
int stateOffOn = 0;
int stateCirc = 0;
int stateAuto = 0;
int stateAC = 0;
int stateMode = 0;
/*
Modes:
0 = Front
1 = Front & Low
2 = Low
3 = Low & High
4 = High
*/
int stateCompressor = 0;
int stateCondenserFan = 0;
int tempExterior = 0;
int tempInterior = 0;
int tempDischarge = 0;
int tempSet = 0;
int fanSpeed = 0;
// Settings (0 - disabled; 1 - enabled)(Can be turned on with any button)
int settingTempMin = 17; // Minimum set temperature (displayed as LO)
int settingTempMax = 31; // Maximum set temperature (displayed as HI)
int settingFanDownOff = 0; // When the speed is 1 & Fan down button is pressed again, the system will off
int settingFanMax = 7;
// Timers
int timerCondenserFan = 0;
int timerRunning = 0;
// Servo positions
int circPos = 0;
int frontPos = 0;
int highPos = 0;
int lowPos = 0;
int targetCircPos = 0;
int targetFrontPos = 0;
int targetHighPos = 0;
int targetLowPos = 0;
// LCD
int lcdRefreshTimer = 0;
byte fanChar[8] = {
0b00001,
0b10011,
0b11010,
0b00100,
0b01011,
0b11001,
0b10000,
0b00000
};
byte tempChar[8] = {
0b01110,
0b01110,
0b01110,
0b01010,
0b01010,
0b10001,
0b10001,
0b01110
};
byte celciusChar[8] = {
0b11000,
0b11000,
0b00110,
0b01001,
0b01000,
0b01000,
0b01001,
0b00110
};
byte ventDashChar[8] = {
0b11100,
0b00111,
0b00001,
0b00001,
0b00011,
0b00110,
0b01100,
0b11000
};
byte ventFrontChar[8] = {
0b00100,
0b00110,
0b11111,
0b00110,
0b00100,
0b00000,
0b00000,
0b00000
};
byte ventLowChar[8] = {
0b10000,
0b10000,
0b10000,
0b10000,
0b01000,
0b00101,
0b00011,
0b00111
};
byte ventHighChar[8] = {
0b00111,
0b00011,
0b00101,
0b01000,
0b10000,
0b10000,
0b10000,
0b10000
};
byte circChar[8] = {
0b00100,
0b00110,
0b11111,
0b10110,
0b10100,
0b10000,
0b10000,
0b11111
};
float rawToCelcius(float rawValue) {
// Temp Sensor reference: https://docs.wokwi.com/parts/wokwi-ntc-temperature-sensor
const float BETA = 3950;
float tempCelcius = 1 / (log(1 / (1023. / rawValue - 1)) / BETA + 1.0 / 298.15) - 273.15;
return tempCelcius + 0.1;
}
void lcdDisplay() {
if (stateOffOn == 1 && digitalRead(pinSensorKeyON) == 0) {
lcd.display();
lcd.backlight();
if (lcdRefreshTimer == 1) {
// Fan
lcd.home();
lcd.write(0);
lcd.print(fanSpeed);
// Set Temperature
lcd.setCursor(6, 0);
lcd.print("Set:");
if (tempSet > settingTempMin && tempSet < settingTempMax) {
lcd.print(tempSet);
lcd.write(2);
} else {
if (tempSet == settingTempMin) {
lcd.print("LO ");
} else if (tempSet == settingTempMax) {
lcd.print("HI ");
}
}
// Auto
lcd.setCursor(0, 1);
if (stateAuto == 1) {
lcd.print("AUTO");
} else {
lcd.print(" ");
}
// A/C
lcd.setCursor(17, 0);
if (stateAC == 1) {
lcd.print("A/C");
} else {
lcd.print(" ");
}
// Outside Temp
lcd.setCursor(3, 2);
lcd.write(1);
lcd.print(tempExterior);
lcd.write(2);
// Circulation
lcd.setCursor(8,2);
if (stateCirc == 1) {
lcd.write(7);
} else {
lcd.print("F");
}
// Vent Mode
lcd.setCursor(9,2);
lcd.write(3);
// Front
lcd.setCursor(10,2);
if (stateMode <= 1) {
lcd.write(4);
} else {
lcd.print(" ");
}
// Low
lcd.setCursor(9,3);
if (stateMode >= 1 && stateMode <= 3) {
lcd.write(5);
} else {
lcd.print(" ");
}
// High
lcd.setCursor(9,1);
if (stateMode >= 3) {
lcd.write(6);
} else {
lcd.print(" ");
}
// Current Temp
lcd.setCursor(12, 2);
lcd.write(1);
lcd.print(tempInterior);
lcd.write(2);
lcdRefreshTimer = 0;
} else {
lcdRefreshTimer++;
}
} else {
lcd.clear();
lcd.noBacklight();
lcd.noDisplay();
}
}
void setup() {
// put your setup code here, to run once:
lcd.begin(20,4);
lcd.createChar(0, fanChar);
lcd.createChar(1, tempChar);
lcd.createChar(2, celciusChar);
lcd.createChar(3, ventDashChar);
lcd.createChar(4, ventFrontChar);
lcd.createChar(5, ventLowChar);
lcd.createChar(6, ventHighChar);
lcd.createChar(7, circChar);
lcd.clear();
// If buttons aren't connected, comment the pinMode()
pinMode(pinSensorKeyON, INPUT_PULLUP);
pinMode(pinSensorAlternator, INPUT_PULLUP);
pinMode(pinSensorInterior, INPUT_PULLUP);
pinMode(pinSensorDischarge, INPUT_PULLUP);
pinMode(pinOffOnBtn, INPUT_PULLUP);
pinMode(pinAutoBtn, INPUT_PULLUP);
pinMode(pinModeBtn, INPUT_PULLUP);
pinMode(pinAcBtn, INPUT_PULLUP);
pinMode(pinCircBtn, INPUT_PULLUP);
pinMode(pinTempUpBtn, INPUT_PULLUP);
pinMode(pinTempDownBtn, INPUT_PULLUP);
pinMode(pinFanUpBtn, INPUT_PULLUP);
pinMode(pinFanDownBtn, INPUT_PULLUP);
pinMode(pinRelayFan, OUTPUT);
pinMode(pinRelayCompressor, OUTPUT);
pinMode(pinRelayCondenserFan, OUTPUT);
frontPos = 0;
servoVentFront.attach(pinServoVentFront);
servoVentFront.write(0);
highPos = 0;
servoVentHigh.attach(pinServoVentHigh);
servoVentHigh.write(0);
lowPos = 0;
servoVentLow.attach(pinServoVentLow);
servoVentLow.write(0);
circPos = 0;
servoCirc.attach(pinServoCirc);
servoCirc.write(0);
stateOffOn = 0;
stateMode = 0;
stateCirc = 1;
stateAuto = 0;
stateAC = 1;
stateCompressor = 0;
stateCondenserFan = 0;
tempSet = 24;
fanSpeed = 1;
stateOffOn = 0;
stateCirc = 1;
stateAuto = 0;
stateAC = 1;
stateMode = 0;
stateCompressor = 0;
stateCondenserFan = 0;
tempSet = 25;
fanSpeed = 1;
}
void loop() {
// put your main code here, to run repeatedly:
delay(100);
// Read button/sensor inputs
int keyOn = digitalRead(pinSensorKeyON) == 0;
int charging = digitalRead(pinSensorAlternator) == 0 && keyOn == 1;
btnOffOn = digitalRead(pinOffOnBtn) == 0;
btnAuto = digitalRead(pinAutoBtn) == 0;
btnMode = digitalRead(pinModeBtn) == 0;
btnCirc = digitalRead(pinCircBtn) == 0;
btnAC = digitalRead(pinAcBtn) == 0;
btnTempUp = digitalRead(pinTempUpBtn) == 0;
btnTempDown = digitalRead(pinTempDownBtn) == 0;
btnFanUp = digitalRead(pinFanUpBtn) == 0;
btnFanDown = digitalRead(pinFanDownBtn) == 0;
float rawSensorExterior = analogRead(pinSensorExterior);
tempExterior = rawToCelcius(rawSensorExterior);
float rawSensorInterior = analogRead(pinSensorInterior);
tempInterior = rawToCelcius(rawSensorInterior);
float rawSensorDischarge = analogRead(pinSensorDischarge);
tempDischarge = rawToCelcius(rawSensorDischarge);
int tempDiff = tempInterior - tempSet;
// Button state changed?
btnOffOn = btnOffOn > lastBtnOffOn;
btnTempUp = btnTempUp > lastBtnTempUp;
btnTempDown = btnTempDown > lastBtnTempDown;
btnFanUp = btnFanUp > lastBtnFanUp;
btnFanDown = btnFanDown > lastBtnFanDown;
lastBtnOffOn = btnOffOn;
lastBtnAuto = btnAuto;
lastBtnMode = btnMode;
lastBtnCirc = btnCirc;
lastBtnAC = btnAC;
lastBtnTempUp = btnTempUp;
lastBtnTempDown = btnTempDown;
lastBtnFanUp = btnFanUp;
lastBtnFanDown = btnFanDown;
// Change values
if (stateOffOn == 1 && keyOn == 1) {
// Off State
if (btnOffOn == 1) { stateOffOn = 0; }
// Auto
if (btnAuto == 1) {
if (stateAuto == 1) {
stateAuto = 0;
} else {
stateAuto = 1;
}
}
// Mode
if (btnMode == 1) {
if (stateMode < 4) {
stateMode++;
} else {
stateMode = 0;
}
}
// Circ
if (btnCirc == 1) {
if (stateCirc == 1) {
stateCirc = 0;
} else {
stateCirc = 1;
}
}
// A/C
if (btnAC == 1) {
if (stateAC == 1) {
stateAC = 0;
} else {
stateAC = 1;
}
}
// Set Temperature
if (btnTempUp == 1 && tempSet < settingTempMax) {
tempSet++;
}
if (btnTempDown == 1 && tempSet > settingTempMin) {
tempSet--;
}
// Fan
if (stateAuto == 1) {
if (btnFanUp == 1 || btnFanDown == 1) {
stateAuto = 0;
} else {
int diff = tempDiff + 1;
int targetSpeed = constrain(diff, 1, settingFanMax);
if (fanSpeed < targetSpeed) { fanSpeed++; } else if (fanSpeed > targetSpeed) { fanSpeed--; }
}
} else {
if ((btnFanUp == 1 && fanSpeed < settingFanMax) || fanSpeed < 1) {
fanSpeed++;
}
if (btnFanDown == 1) {
if (fanSpeed == 1 && settingFanDownOff == 1) {
stateOffOn = 0;
} else {
if (fanSpeed > 1) { fanSpeed--; }
}
}
}
// Compressor
if (stateAC == 1 && charging == 1) {
if (stateCompressor == 1) {
// if (tempDischarge <= (tempSet - 5) || tempInterior < tempSet) { stateCompressor = 0; }
if (tempDischarge <= (tempSet - 5)) { stateCompressor = 0; }
} else {
// if (tempDischarge >= (tempSet - 1) && tempInterior > tempSet) { stateCompressor = 1; }
if (tempDischarge >= (tempSet - 1)) { stateCompressor = 1; }
}
} else {
stateCompressor = 0;
}
} else {
if ((btnOffOn == 1 || btnTempDown == 1 || btnTempUp == 1) && keyOn == 1) { stateOffOn = 1; } // Off/On and Temperature button
if ((btnFanDown == 1 || btnFanUp == 1) && keyOn == 1) { stateOffOn = 1; stateAuto = 0; fanSpeed = 1; } // Speed button
if (btnAuto == 1 && keyOn == 1) { stateOffOn = 1; stateAuto = 1; } // Auto button
}
// Set relays
// A/C system based
if (stateOffOn == 1 && keyOn == 1) {
// Fan
digitalWrite(pinRelayFan, HIGH);
// int percent = (fanSpeed / settingFanMax) * 100;
// float multiplier = percent / 100;
// analogWrite(pinFanPWM, 255 * multiplier);
} else {
digitalWrite(pinRelayFan, LOW);
digitalWrite(pinRelayCompressor, LOW);
digitalWrite(pinRelayCondenserFan, LOW);
}
// Ignition based
if (keyOn == 1) {
digitalWrite(pinRelayServos, HIGH);
// Mode Servo
// Front
if (stateMode <= 1) {
targetFrontPos = 180;
} else {
targetFrontPos = 0;
}
// Low
if (stateMode >= 1 && stateMode <= 3) {
targetLowPos = 180;
} else {
targetLowPos = 0;
}
// High
if (stateMode >= 3) {
targetHighPos = 180;
} else {
targetHighPos = 0;
}
frontPos = (targetFrontPos + frontPos) / 2;
servoVentFront.write(frontPos);
lowPos = (targetLowPos + lowPos) / 2;
servoVentLow.write(lowPos);
highPos = (targetHighPos + highPos) / 2;
servoVentHigh.write(highPos);
// Circulation Servo
if (stateCirc == 1) {
targetCircPos = 180;
} else {
targetCircPos = 0;
}
circPos = (targetCircPos + circPos) / 2;
servoCirc.write(circPos);
} else {
digitalWrite(pinRelayServos, LOW);
}
// Compressor & Condenser Fan
if (stateCompressor == 1 && stateOffOn == 1 && charging == 1) {
digitalWrite(pinRelayCompressor, HIGH);
if (timerCondenserFan == 10) {
digitalWrite(pinRelayCondenserFan, HIGH);
} else {
digitalWrite(pinRelayCondenserFan, LOW);
timerCondenserFan++;
}
} else {
digitalWrite(pinRelayCompressor, LOW);
digitalWrite(pinRelayCondenserFan, LOW);
timerCondenserFan = 0;
}
lcdDisplay();
}