/* ESP-32 Airconditioning system control */ //SYSTEM PARAMETERS
//Input Pins
#include <WiFi.h> const uint8_t powerPin = 36;
#include <EasyButton.h> const uint8_t modePin = 39;
#include <DHTesp.h> const uint8_t tempDownPin = 34;
#include <AsyncMqttClient.h> const uint8_t tempUpPin = 35;
#include <U8g2lib.h> const uint8_t DHTPin = 32;
#include <WiFiClient.h>
#include <WebServer.h> //Output Pins
#include <ESPmDNS.h> const uint8_t buzzerPin=26;
#include <Update.h> const uint8_t compressorPin = 33;
const uint8_t fanPin = 25;
//Network Parameters
#define WIFI_SSID "IoTnet" //DHT Sensor
#define WIFI_PASSWORD "1l4E1g0R9@2n9D" DHTesp dht;
#define MQTT_HOST IPAddress(10, 26, 178, 10) int dhtPin = 32;
#define MQTT_PORT 1883 //const uint8_t tempSensor = A4;
String mqttTopic = "ac_GuestRoom";
const char* host = "esp32"; //System Variables
WebServer server(80); float sensorTemperature;
String sensorTempOld;
//OLED Display Driver float setTemperature = 21.00;
U8G2_SH1106_128X64_NONAME_1_HW_I2C float setTempOld = 0;
u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); long readTempTimer = 0;
int acPower = 0;
//External Timers int acMode = 1;
extern "C" { char ip[32];
#include "freertos/FreeRTOS.h" char acPowerChar[15];
#include "freertos/timers.h" char acModeChar[15];
} char acSetTempChar[15];
TimerHandle_t mqttReconnectTimer; char acTempSensor[15];
TimerHandle_t wifiReconnectTimer; String IPaddress;
//Local Button Parameters void connectToWifi() {
#define btnPower_PIN 36 Serial.println("Connecting to Wi-Fi...");
#define btnMode_PIN 39 WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#define btnTempUp_PIN 35 }
#define btnTempDn_PIN 34
void connectToMqtt() {
//Declare EasyButtons Serial.println("Connecting to MQTT...");
EasyButton btnPower(btnPower_PIN); mqttClient.connect();
EasyButton btnMode(btnMode_PIN, 35, true, false); }
EasyButton btnTempUp(btnTempUp_PIN, 35, true,
false); void WiFiEvent(WiFiEvent_t event) {
EasyButton btnTempDn(btnTempDn_PIN, 35, true, Serial.printf("[WiFi-event] event: %d\n", event);
false); switch(event) {
case SYSTEM_EVENT_STA_GOT_IP:
//Define Async MQTT Client Serial.println("WiFi connected");
AsyncMqttClient mqttClient; Serial.println("IP address: ");
Serial.println(WiFi.localIP());
//MQTT Variables connectToMqtt();
char mqttCmndPower[30]; IPaddress = "NETWORK: " +
char mqttCmndMode[30]; WiFi.localIP().toString();
char mqttCmndTemp[30]; IPaddress.toCharArray(ip,32);
char mqttStatPower[30]; break;
char mqttStatMode[30]; case SYSTEM_EVENT_STA_DISCONNECTED:
char mqttStatTemp[30]; Serial.println("WiFi lost connection");
char mqttStatSensor[30];
xTimerStop(mqttReconnectTimer, 0); // ensure }
we don't reconnect to MQTT while reconnecting to
Wi-Fi void onMqttUnsubscribe(uint16_t packetId) {
xTimerStart(wifiReconnectTimer, 0); Serial.println("Unsubscribe acknowledged.");
IPaddress = "NETWORK OFFLINE"; Serial.print(" packetId: ");
IPaddress.toCharArray(ip,32); Serial.println(packetId);
break; }
}
} void onMqttMessage(char* topic, char* payload,
AsyncMqttClientMessageProperties properties, size_t
void onMqttConnect(bool sessionPresent) { len, size_t index, size_t total) {
Serial.println("Connected to MQTT."); Serial.print(topic);
Serial.print("Session present: "); Serial.print(":");
Serial.println(sessionPresent); Serial.println(payload);
uint16_t packetIdSub1 = String strMqttCmndPower = "cmnd/" + mqttTopic +
mqttClient.subscribe(mqttCmndPower, 0); "/POWER";
Serial.print("Subscribing to Topic: ~/POWER, String strMqttCmndMode = "cmnd/" + mqttTopic +
packetId: "); "/MODE";
Serial.println(packetIdSub1); String strMqttCmndTemp = "cmnd/" + mqttTopic +
uint16_t packetIdSub2 = "/TEMP";
mqttClient.subscribe(mqttCmndMode, 0); String mqttSubTopic=String (topic);
Serial.print("Subscribing to Topic: ~/MODE, packetId: String mqttSubPayload=String(payload);
"); if (mqttSubTopic==strMqttCmndPower) {
Serial.println(packetIdSub2); if (mqttSubPayload=="1"){
uint16_t packetIdSub3 = acPower=1;
mqttClient.subscribe(mqttCmndTemp, 0); } else {
Serial.print("Subscribing to Topic: ~/TEMP, packetId: acPower=0;
"); }
Serial.println(packetIdSub3); }
/*mqttClient.publish("test/lol", 0, true, "test 1"); if (mqttSubTopic==strMqttCmndMode) {
Serial.println("Publishing at QoS 0"); if (mqttSubPayload=="1"){
uint16_t packetIdPub1 = acMode=1;
mqttClient.publish("test/lol", 1, false, "test 2"); } else {
Serial.print("Publishing at QoS 1, packetId: "); acMode=0;
Serial.println(packetIdPub1); }
uint16_t packetIdPub2 = }
mqttClient.publish("test/lol", 2, false, "test 3"); if (mqttSubTopic==strMqttCmndTemp) {
Serial.print("Publishing at QoS 2, packetId: "); setTemperature=mqttSubPayload.toFloat();
Serial.println(packetIdPub2);*/ Serial.println(setTemperature);
pubMqtt(); }
} }
void void onMqttPublish(uint16_t packetId) {
onMqttDisconnect(AsyncMqttClientDisconnectReason Serial.println("Publish acknowledged.");
reason) { Serial.print(" packetId: ");
Serial.println("Disconnected from MQTT."); Serial.println(packetId);
}
if (WiFi.isConnected()) {
xTimerStart(mqttReconnectTimer, 0); void btnPowerPressed() {
} Serial.println("POWER Button has been pressed!");
} if (acPower==0) {
acPower=1;
void onMqttSubscribe(uint16_t packetId, uint8_t qos) } else {
{ acPower=0;
Serial.println("Subscribe acknowledged."); }
Serial.print(" packetId: "); pubMqtt();
Serial.println(packetId); beep();
Serial.print(" qos: "); }
Serial.println(qos);
void btnModePressed() { }
Serial.println("MODE Button has been pressed!");
if (acPower==1){ /*
if (acMode==1){ * Login page
acMode=0; */
} else {
acMode=1; const char* loginIndex =
} "<form name='loginForm'>"
//powerState=false; "<table width='20%' bgcolor='A09F9F'
pubMqtt(); align='center'>"
beep(); "<tr>"
} "<td colspan=2>"
} "<center><font size=4><b>ESP32 Login
Page</b></font></center>"
void btnTempUpPressed() { "<br>"
Serial.println("TEMP UP Button has been pressed!"); "</td>"
if (acPower==1){ "<br>"
if (setTemperature < 26) { "<br>"
setTemperature++; "</tr>"
} "<td>Username:</td>"
beep(); "<td><input type='text' size=25
} name='userid'><br></td>"
} "</tr>"
"<br>"
void btnTempDnPressed() { "<br>"
Serial.println("TEMP DOWN Button has been "<tr>"
pressed!"); "<td>Password:</td>"
if (acPower==1){ "<td><input type='Password' size=25
if (setTemperature > 16) { name='pwd'><br></td>"
setTemperature--; "<br>"
} "<br>"
beep(); "</tr>"
} "<tr>"
} "<td><input type='submit'
onclick='check(this.form)' value='Login'></td>"
void beep() { "</tr>"
digitalWrite(buzzerPin, HIGH); "</table>"
delay(100); "</form>"
digitalWrite(buzzerPin, LOW); "<script>"
} "function check(form)"
"{"
void pubMqtt(){ "if(form.userid.value=='admin' &&
if (acPower==0) { form.pwd.value=='admin')"
uint16_t packetIdPub1 = "{"
mqttClient.publish(mqttStatPower, 1, false, "0"); "window.open('/serverIndex')"
} else { "}"
uint16_t packetIdPub1 = "else"
mqttClient.publish(mqttStatPower, 1, false, "1"); "{"
} " alert('Error Password or Username')/*displays
if (acMode==0){ error message*/"
uint16_t packetIdPub2 = "}"
mqttClient.publish(mqttStatMode, 1, false, "0"); "}"
} else { "</script>";
uint16_t packetIdPub2 =
mqttClient.publish(mqttStatMode, 1, false, "1"); /*
} * Server Index Page
uint16_t packetIdPub3 = */
mqttClient.publish(mqttStatTemp, 1, false,
acSetTempChar); const char* serverIndex =
"<script digitalWrite(fanPin, LOW);
src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.
1/jquery.min.js'></script>" dht.setup(dhtPin, DHTesp::DHT22);
"<form method='POST' action='#'
enctype='multipart/form-data' id='upload_form'>" //Initialize Buttons
"<input type='file' name='update'>" btnPower.begin();
"<input type='submit' value='Update'>" btnMode.begin();
"</form>" btnTempUp.begin();
"<div id='prg'>progress: 0%</div>" btnTempDn.begin();
"<script>"
"$('form').submit(function(e){" btnPower.onPressed(btnPowerPressed);
"e.preventDefault();" btnMode.onPressed(btnModePressed);
"var form = $('#upload_form')[0];" btnTempUp.onPressed(btnTempUpPressed);
"var data = new FormData(form);" btnTempDn.onPressed(btnTempDnPressed);
" $.ajax({"
"url: '/update'," //Initialize MQTT params
"type: 'POST'," String strMqttCmndPower = "cmnd/" + mqttTopic +
"data: data," "/POWER";
"contentType: false," String strMqttCmndMode = "cmnd/" + mqttTopic +
"processData:false," "/MODE";
"xhr: function() {" String strMqttCmndTemp = "cmnd/" + mqttTopic +
"var xhr = new window.XMLHttpRequest();" "/TEMP";
"xhr.upload.addEventListener('progress', String strMqttStatPower = "stat/" + mqttTopic +
function(evt) {" "/POWER";
"if (evt.lengthComputable) {" String strMqttStatMode = "stat/" + mqttTopic +
"var per = evt.loaded / evt.total;" "/MODE";
"$('#prg').html('progress: ' + Math.round(per*100) + String strMqttStatTemp = "stat/" + mqttTopic +
'%');" "/TEMP";
"}" String strMqttSensorTemp = "stat/" + mqttTopic +
"}, false);" "/SENSOR";
"return xhr;"
"}," strMqttCmndPower.toCharArray(mqttCmndPower,30
"success:function(d, s) {" );
"console.log('success!')"
"}," strMqttCmndMode.toCharArray(mqttCmndMode,30);
"error: function (a, b, c) {"
"}" strMqttCmndTemp.toCharArray(mqttCmndTemp,30);
"});" strMqttStatPower.toCharArray(mqttStatPower,30);
"});" strMqttStatMode.toCharArray(mqttStatMode,30);
"</script>"; strMqttStatTemp.toCharArray(mqttStatTemp,30);
void setup() { strMqttSensorTemp.toCharArray(mqttStatSensor,30);
Serial.begin(115200);
u8g2.begin(); // Add the callback function to be called when the
/*Initial display*/ button1 is pressed.
u8g2.firstPage(); //button1.onPressed(onButton1Pressed);
do { //button1.onPressedFor(2000,
u8g2.setFont(u8g2_font_8x13B_tf); onPressedForDuration);
u8g2.drawStr(2,20,"INITIALIZING..."); // Add the callback function to be called when the
} while ( u8g2.nextPage() ); button2 is pressed.
//button2.onPressed(onButton2Pressed);
//Set IO pin mode beep();
//pinMode(boardLED, OUTPUT); pubMqtt();
//pinMode(dhtPin, INPUT);
pinMode(buzzerPin, OUTPUT); mqttReconnectTimer = xTimerCreate("mqttTimer",
pinMode(compressorPin, OUTPUT); pdMS_TO_TICKS(2000), pdFALSE, (void*)0,
pinMode(fanPin, OUTPUT); reinterpret_cast<TimerCallbackFunction_t>(connectT
digitalWrite(buzzerPin, LOW); oMqtt));
digitalWrite(compressorPin, LOW);
wifiReconnectTimer = xTimerCreate("wifiTimer", char acTempMqtt[30];
pdMS_TO_TICKS(2000), pdFALSE, (void*)0, strSensor.toCharArray(acTempMqtt,30);
reinterpret_cast<TimerCallbackFunction_t>(connectT uint16_t packetIdPub3 =
oWifi)); mqttClient.publish(mqttStatSensor, 1, false,
acTempMqtt);
WiFi.onEvent(WiFiEvent); strSensor.remove(2,10);
strSensor.toCharArray(acTempSensor,30);
mqttClient.onConnect(onMqttConnect); }
mqttClient.onDisconnect(onMqttDisconnect); readTempTimer=now;
mqttClient.onSubscribe(onMqttSubscribe); }
mqttClient.onUnsubscribe(onMqttUnsubscribe); motorControl();
mqttClient.onMessage(onMqttMessage); server.handleClient();
mqttClient.onPublish(onMqttPublish); updateDisplay();
mqttClient.setServer(MQTT_HOST, MQTT_PORT); }
IPaddress = "Connecting..."; void motorControl(){
IPaddress.toCharArray(ip,18); if (acPower==1) { //Sysyem power is ON
digitalWrite(fanPin, HIGH);
connectToWifi(); if (acMode==1){ //Cooling mode selected
ota(); if (sensorTemperature >= setTemperature + 1) {
} digitalWrite(compressorPin, HIGH);
} else if (sensorTemperature <= setTemperature) {
void loop() { digitalWrite(compressorPin, LOW);
btnPower.read(); }
btnMode.read(); } else if (acMode==0) {
btnTempUp.read(); digitalWrite(compressorPin, LOW);
btnTempDn.read(); }
} else if (acPower==0) {
String strSetTemperature = String(setTemperature); digitalWrite(compressorPin, LOW);
strSetTemperature.remove(2,10); //delay(5000);
strSetTemperature.toCharArray(acSetTempChar,15); digitalWrite(fanPin, LOW);
if (setTemperature != setTempOld) { }
uint16_t packetIdPub1 = }
mqttClient.publish("stat/ac_GuestRoom/TEMP", 1, void updateDisplay() {
false, acSetTempChar); if (acPower==0){
setTempOld=setTemperature; u8g2.firstPage();
} do {
u8g2.setFont(u8g2_font_8x13B_tf);
String strACMode; u8g2.drawStr(2,20,"Standby Mode...");
if (acMode==1) { } while ( u8g2.nextPage() );
strACMode="COOL"; } else {
} else { u8g2.firstPage();
strACMode="FAN"; do {
} u8g2.setFont(u8g2_font_fur49_tn);
strACMode.toCharArray(acModeChar,15); u8g2.drawStr(0,50,acSetTempChar);
long now = millis(); u8g2.setFont(u8g2_font_crox5h_tf);
if (now > readTempTimer + 2000) { u8g2.drawStr(92,29,acTempSensor);
sensorTemperature = dht.getTemperature();
String strSensor = String(sensorTemperature); u8g2.setFont(u8g2_font_logisoso18_tf);
strSensor.remove(2,10); u8g2.drawStr(82,52,acModeChar);
Serial.print("Sensor Temperature: ");
Serial.println(strSensor); u8g2.drawHLine(0,54,128);
Serial.print("Sensor Humidity: "); u8g2.drawHLine(80,32,48);
Serial.println(dht.getHumidity()); u8g2.drawVLine(80,0,54);
if (strSensor != sensorTempOld && strSensor != u8g2.setFont(u8g2_font_5x7_tr);
"nan"){
sensorTempOld = strSensor; u8g2.drawStr(0,64,ip);
//String strSensor = String(sensorTemperature); u8g2.drawStr(82,8,"ROOM TEMP");
} while ( u8g2.nextPage() ); }
}
}
void ota(){
/*use mdns for host name resolution*/
if (!MDNS.begin(host)) { //http://esp32.local
Serial.println("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
/*return index page which is stored in serverIndex */
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", loginIndex);
});
server.on("/serverIndex", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
/*handling uploading firmware file */
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ?
"FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n",
upload.filename.c_str());
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_8x13B_tf);
u8g2.drawStr(2,20,"Firmware Update...");
} while ( u8g2.nextPage() );
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) {
//start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) !=
upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the
current progress
Serial.printf("Update Success:
%u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
server.begin();