// CD74HC4067
// 16-Channel Analog Multiplexer
// Demultiplexing not implemented for this simulation.
// https://www.ti.com/lit/ds/symlink/cd74hc4067.pdf
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define S0 18
#define S1 19
#define S2 22
#define S3 23
#define R0 32
#define R1 33
#define R2 25
#define R3 26
#define COM 34
#define NP_PIN 4
#define WAIT_TIME 10000
#define FAN_TIME 110000
#define TEMP_DIFF 0.5
#define SPA_TO_POOL_WAIT 60000
#define IDLE 0
#define HEAT 1
#define DEFROST 2
#define HIGHPRESSURE 3
#define LOWPRESSURE 4
#define NOFLOW 5
#define WAIT 6
#define FAN 7
#define DEFROST_MIN 3.8
#define DEFROST_MAX 9
int lastWait = millis();
int lastPoolWait = millis();
int highPressureSwitch, lowPressureSwitch, spaMode, flowSwitch;
float waterIn, waterOut, airIn, airOut, defrostLower, defrostUpper;
float spaSetPoint, poolSetPoint, setPoint;
int fanRelay, compressorRelay, defrostRelay, spaRelay;
int state = WAIT;
const uint8_t controlPins[] = { S0, S1, S2, S3 };
const char *vstate[] = { "IDLE", "HEAT", "DEFROST", "HIGH", "LOW", "NOFLOW", "WAIT", "FAN" };
const uint8_t muxChannels [16][4] = {
{0,0,0,0},
{1,0,0,0},
{0,1,0,0},
{1,1,0,0},
{0,0,1,0},
{1,0,1,0},
{0,1,1,0},
{1,1,1,0},
{0,0,0,1},
{1,0,0,1},
{0,1,0,1},
{1,1,0,1},
{0,0,1,1},
{1,0,1,1},
{0,1,1,1},
{1,1,1,1}
};
float readMuxAnalog(int channel)
{
for(int i = 0; i < 4; i ++)
{
digitalWrite(controlPins[i], muxChannels[channel][i]);
}
delay(10);
return analogRead(COM);
//return adc1_get_raw(ADC1_CHANNEL_6);
}
int readMuxDigital(int channel)
{
for(int i = 0; i < 4; i ++)
{
digitalWrite(controlPins[i], muxChannels[channel][i]);
}
delay(10);
return analogRead(COM)>128;
//return adc1_get_raw(ADC1_CHANNEL_6);
}
double Temp(int RawADC) {
return 1 / (log(1 / (4095. / RawADC - 1)) / 3950 + 1.0 / 298.15) - 273.15;
}
//d=adc1_get_raw(ADC1_CHANNEL_7);
//aC = 1 / (log(1 / (4095. / a - 1)) / BETA + 1.0 / 298.15) - 273.15;
void setRelays()
{
digitalWrite(R0, fanRelay);
digitalWrite(R1, compressorRelay);
digitalWrite(R2, defrostRelay);
digitalWrite(R3, spaRelay);
}
void setup()
{
pinMode(S0, OUTPUT);
pinMode(S1, OUTPUT);
pinMode(S2, OUTPUT);
pinMode(S3, OUTPUT);
pinMode(R0, OUTPUT);
pinMode(R1, OUTPUT);
pinMode(R2, OUTPUT);
pinMode(R3, OUTPUT);
fanRelay = false;
compressorRelay = false;
defrostRelay = false;
spaRelay = false;
setRelays();
spaSetPoint = 38;
poolSetPoint = 32;
setPoint = poolSetPoint - TEMP_DIFF;
Serial.begin(115200);
Serial.println("ESP Smart IoT Pool Heat Pump Controller");
}
void logSerial()
{
Serial.print("STATE:");
Serial.print(vstate[state]);
if(highPressureSwitch) Serial.print((" HIGH"));
if(lowPressureSwitch) Serial.print((" LOW"));
if(flowSwitch) Serial.print((" FLOW"));
if(spaMode) Serial.print((" SPA"));
Serial.print("\t");
if(state==WAIT)
{
Serial.print("-");
Serial.print((WAIT_TIME+1999-(millis()-lastWait))/1000);
}
if(state==FAN) {
Serial.print("-");
Serial.print((FAN_TIME+1999-(millis()-lastWait))/1000);
}
if(state==HEAT)
{
Serial.print(((millis()-lastWait))/1000);
}
if(state==DEFROST)
{
Serial.print(((millis()-lastWait))/1000);
}
Serial.print("\t");
Serial.print(waterIn);
Serial.print(" => ");
Serial.print(setPoint);
Serial.println("\t\t");
Serial.print("poolSetPoint:");
Serial.print(poolSetPoint);
Serial.print("\t");
Serial.print("spaSetPoint:");
Serial.print(spaSetPoint);
Serial.print("\t");
Serial.print("waterIn:");
Serial.print(waterIn);
Serial.print(" \t");
Serial.print("waterOut:");
Serial.print(waterOut);
Serial.println();
Serial.print("airIn:");
Serial.print(airIn);
Serial.print(" \t");
Serial.print("airOut:");
Serial.print(airOut);
Serial.print(" \t");
Serial.print("defrostLower:");
Serial.print(defrostLower);
Serial.print("\t");
Serial.print("defrostUpper:");
Serial.print(defrostUpper);
Serial.println();
Serial.println();
}
void readSensors()
{
waterIn=Temp(readMuxAnalog(0));
waterOut=Temp(readMuxAnalog(1));
airIn=Temp(readMuxAnalog(2));
airOut=Temp(readMuxAnalog(3));
defrostLower=Temp(readMuxAnalog(4));
defrostUpper=Temp(readMuxAnalog(5));
highPressureSwitch=readMuxDigital(8);
lowPressureSwitch=readMuxDigital(7);
spaMode=readMuxDigital(9);
flowSwitch=readMuxDigital(6);
}
void adjustSpaMode()
{
if(spaMode)
{
setPoint = spaSetPoint - TEMP_DIFF;
spaRelay = true;
lastPoolWait=millis();
} else
{
if(millis() > lastPoolWait + SPA_TO_POOL_WAIT)
{
setPoint = poolSetPoint - TEMP_DIFF;
}
spaRelay = false;
}
}
void loop()
{
readSensors();
adjustSpaMode();
setRelays();
if(lowPressureSwitch) state = LOWPRESSURE;
if(highPressureSwitch) state = HIGHPRESSURE;
if(flowSwitch) state = NOFLOW;
logSerial();
switch(state)
{
case IDLE:
if(setPoint > waterIn)
{
if((defrostUpper + defrostLower)/2 <= DEFROST_MIN)
{
lastWait=millis();
state = DEFROST;
} else
{
fanRelay = false;
lastWait = millis();
state=WAIT;
}
}
break;
case DEFROST:
compressorRelay = false;
if((defrostUpper + defrostLower)/2 <= DEFROST_MAX)
{
if(setPoint > waterIn)
{
if(airIn > DEFROST_MIN)
{
fanRelay = true;
} else
{
fanRelay = false;
}
compressorRelay = false;
} else
{
fanRelay = false;
compressorRelay = false;
}
state = DEFROST;
}
else
{
state = WAIT;
}
break;
case FAN:
if( (millis()-lastWait) > FAN_TIME)
{
lastWait=millis();
if((defrostUpper + defrostLower)/2 <= DEFROST_MIN)
{
state = DEFROST;
lastWait=millis();
break;
}
if(setPoint > waterIn)
{
compressorRelay = true;
fanRelay = true;
state=HEAT;
} else
{
fanRelay = false;
state=WAIT;
}
}
break;
case HEAT:
if((defrostUpper + defrostLower)/2 <= DEFROST_MIN)
{
state = DEFROST;
lastWait=millis();
break;
}
if(setPoint <= waterIn-(TEMP_DIFF*2))
{
state=FAN;
compressorRelay = false;
fanRelay = true;
lastWait=millis();
}
break;
case WAIT:
if( (millis()-lastWait) > WAIT_TIME)
{
lastWait=millis();
if(setPoint > waterIn )
{
compressorRelay = false;
fanRelay = true;
state=FAN;
} else
{
fanRelay = false;
compressorRelay = false;
state=IDLE;
}
}
break;
default:
compressorRelay = false;
fanRelay = false;
state = WAIT;
}
sleep(1);
}