top of page
Writer's pictureRamesh G

Web Server Based Temperature Controller With EEPROM and Auto/Manual Mode


In this tutorial, I 'll Publish how to controlling the Room heater through Relay channel board using web server over WiFi using NodeMCU, DS18B20 and OLED display. In this project, the temperature controller have Auto and Manual mode function.


The manual mode is manually ON / OFF the output in the HTML page and has been implemented in the basic version of the WiFi temperature controller with the possibility of switching automatic mode.


The Automatic Mode is active until the target temperature + hysteresis is reached. And you change and set the target temperature and Hysteresis in the HTML page and has been implemented in the advanced version of the WiFi temperature controller with the possibility of switching manual mode.

Example:

  • Target temperature: 31.75 °C

  • Hysteresis: 0.25 °C

  • Measured data: 31.49 °C

  • Output: ON (target temperature + hysteresis)

Condition:

If the temperature reaches 32.01 °C, the output is Turn OFF.

And output is not reactivated until the temperature reaches 31.49 °C or lower.


In order to keep the set values (Temperature & Hysteresis) of the thermostat even after a power failure, they are stored in the EEPROM memory.


Circuit Diagram




Components Required

0.96 OLED 4wire Module - 1no

Node MU ESP8266 12E Dev Module- 1 no

DS18B20 with Probe

Relay single channel- 1no

Resistor- 4k7 ohms



DS18B20

DS18B20 is a temperature sensor of Maxim. The single-chip microcomputer can communicate with DS18B20 through 1-Wire protocol and finally read the temperature. The hardware interface of the 1-Wire bus is very simple, just connect the data pin of DS18B20 to an IO port of the microcontroller.




Installing the library


To install the library navigate to the Sketch > Include Library > Manage Libraries… Wait for Library Manager to download libraries index and update list of installed libraries.


Download Adafruit_SSD1306_Library , we need to use this library for SSD1306 OLED display

Download Adafruit_GFX_Library , we need to use this library for Graphics


To interface with the DS18B20 temperature sensor, you need to install the One Wire library .

Open your Arduino IDE and go to Sketch > Include Library > Manage Libraries. The Library Manager should open. Type “onewire” in the search box and install the OneWire library by Paul Stoffregen.


Download Dallas Library , we need to use this library for temperature measurement.


In your Arduino IDE, to install the libraries go to Sketch > Include Library > Add .ZIP library… and select the library you’ve just downloaded.


After installing the required libraries, copy the following code to your Arduino IDE.


arduino code




const char *ssid = "TP-Link_3200"; //your ssid

const char *password = "95001121379884265554"; //your wifi password

#include <ESP8266WiFi.h>

#include <ESP8266WebServer.h>

#include <WiFiManager.h>

ESP8266WebServer server(80);

#include <DNSServer.h>

#include <EEPROM.h>

#include <OneWire.h>

#include <DallasTemperature.h>


#define ONE_WIRE_BUS 2 //D4 of esp8266 12E

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensorsA(&oneWire);

const int Relay = 14; //D5 of esp8266 12E

unsigned long kase = 0;

String Heater = "OFF";

float TempVal;



#include <SPI.h>

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels

#define SCREEN_HEIGHT 64 // OLED display height, in pixels

#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)

#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


float SysMode;

boolean isFloat(String tString) {

String tBuf;

boolean decPt = false;


if (tString.charAt(0) == '+' || tString.charAt(0) == '-') tBuf = &tString[1];

else tBuf = tString;


for (int x = 0; x < tBuf.length(); x++)

{

if (tBuf.charAt(x) == '.' || tBuf.charAt(x) == ',') {

if (decPt) return false;

else decPt = true;

}

else if (tBuf.charAt(x) < '0' || tBuf.charAt(x) > '9') return false;

}

return true;

}


void writeString(char add, float data)

{

EEPROM.put(add, (data * 1000));

EEPROM.commit();

}



float read_String(char add)

{

float payload = 0;

float data = EEPROM.get(add, payload);

return (data / 1000);

}


void handleRoot() {


String Page = F("<!DOCTYPE html>");

Page += F("<html>");

Page += F("<head>");

Page += "<body style='background-color=powderblue;'>";

Page += F("<meta charset='utf-8'>");

Page += F("<meta http-equiv='Refresh' content='2'; />");

Page += F("<meta name='viewport' content='width=device-width, initial-scale=1'>");

Page += F("<title>ESP8266 smart thermostat</title>");

Page += F("</head>");

Page += F("<body>");

Page += F("<b><center><h3><font color='blue'>ESP8266 Web Server Based Temperature Control With EEPROM and Auto/Manual Mode</h3></font></b>");

Page += F("<b><font color='blue'>Current Temperature:</font></b> ");

Page += String(TempVal);

Page += F(" °C");

Page += F("<center><h4></h4>");

if (SysMode == 0.00) {


Page += F("<form action='/action.html' method='post'>");

Page += "<b><font color=' blue '>Temperature Set Point °C : </font></b><input type='text' id='TFrame' name='TFrame' min='5' max='50' step='0.25' value=" + String(read_String(10)) + ">";

Page += F("<center><h4></h4>");

Page += "<b><font color=' blue '>Hysteresis Set Point °C : </font></b><input type='text' id='TFrame2' name='TFrame2' min='0' max='10' step='0.25' value=" + String(read_String(100)) + ">";

Page += F("<center><h4></h4>");

Page += F("<input type='submit' class='btn btn-success' value='Send'>");

Page += F("<center><h4></h4>");

Page += F("</form>");

Page += F("<a href='manual.html' class='btn btn-primary' role='button'>Manual MODE</a>");

Page += F("<center><h4></h4>");

} else if (SysMode == 1.00) {

if (Heater == "ON") {

Page += F("<a href='RelConPf.html' class='btn btn-tooff' role='button'>Turn OFF</a><br>");

}

if (Heater == "OFF") {

Page += F("<a href='RelConPn.html' class='btn btn-success' role='button'>Turn ON</a><br>");

}

Page += F("<a href='automat.html' class='btn btn-primary' role='button'>Automatic MODE</a><hr>");

}

if (Heater == "ON") {

Page += F("<b><font color='green'>Heater Status: ON</font></b>");

}

if (Heater == "OFF") {

Page += F("<b><font color='red'>Heater Status: OFF</font></b>");

}

Page += F("</body>");

Page += F("</html>");

server.send(200, "text/html", Page);

}


void handleBody() {

if (server.hasArg("TFrame")) {

String target_temp = server.arg("TFrame");

if (isFloat(target_temp)) {

float SetTemppoint = target_temp.toFloat();

writeString(10, SetTemppoint);

} else {

Serial.println(F("No number was entered in the input according to the target temperature!"));

Serial.println(F("Writing into EEPROM prohibited!"));

}

}

if (server.hasArg("TFrame2")) {

String hysteresis = server.arg("TFrame2");

if (isFloat(hysteresis)) {

float SetHss = hysteresis.toFloat();

writeString(100, SetHss);

} else {

Serial.println(F("No number was entered in the input according to the hysteresis!"));

Serial.println(F("Writing into EEPROM prohibited!"));

}

}

String Page = F("<!DOCTYPE html>");

Page += F("<html>");

Page += F("<head>");

Page += F("<meta charset='utf-8'>");

Page += F("<meta http-equiv='Refresh' content='2; url=/' />");

Page += F("<title>ESP8266 Post form</title>");

Page += F("</head>");

Page += F("<body>");

Page += F("<center><h3><font color='red'>ESP Server received data from HTML form</font></h3>");

Page += "<li><b><font color='blue'>Temperature Set Point: </font></b>" + String(read_String(10)) + " °C</li>";

Page += "<li><b><font color='blue'>Hysteresis Set Point: </font></b>" + String(read_String(100)) + " °C</li>";

Page += F("<b><font color='blue'>Loading....</font></b></center>");

Page += F("</body>");

Page += F("</html>");

server.send(200, "text/html", Page);

}


void handleGet() {

String Page = "{\n";

Page += F("\"Hysteresis\":");

Page += String(read_String(100));

Page += F(",\n");

Page += F("\"Target_Temperature\":");

Page += String(read_String(10));

Page += F(",\n");

Page += F("\"Actual_Temperature\":");

Page += String(TempVal) + "\n";

Page += F("}\n");

server.send(200, "application/json", Page);

}


void handleRelConPn() {

Heater = "ON";

digitalWrite(Relay, LOW);

String Page = F("<!DOCTYPE html>");

Page += F("<html>");

Page += F("<head>");

Page += F("<meta charset='utf-8'>");

Page += F("<meta http-equiv='Refresh' content='0; url=/' />");

Page += F("</head>");

Page += F("</html>");

server.send(200, "text/html", Page);

}


void handleAuto() {

writeString(150, 0.00);

SysMode = read_String(150);

String Page = F("<!DOCTYPE html>");

Page += F("<html>");

Page += F("<head>");

Page += F("<meta charset='utf-8'>");

Page += F("<meta http-equiv='Refresh' content='0; url=/' />");

Page += F("</head>");

Page += F("</html>");

server.send(200, "text/html", Page);

Serial.println("Auto");

}

void handleManual() {

writeString(150, 1.00);

SysMode = read_String(150);

String Page = F("<!DOCTYPE html>");

Page += F("<html>");

Page += F("<head>");

Page += F("<meta charset='utf-8'>");

Page += F("<meta http-equiv='Refresh' content='0; url=/' />");

Page += F("</head>");

Page += F("</html>");

server.send(200, "text/html", Page);

Serial.println("Manual Mode");

}

void handleRelConPf() {

Heater = "OFF";

digitalWrite(Relay, HIGH);

String Page = F("<!DOCTYPE html>");

Page += F("<html>");

Page += F("<head>");

Page += F("<meta charset='utf-8'>");

Page += F("<meta http-equiv='Refresh' content='0; url=/' />");

Page += F("</head>");

Page += F("</html>");

server.send(200, "text/html", Page);

}

void setup() {

Serial.begin(115200);

WiFiManager wifiManager;

wifiManager.autoConnect("WiFi_TERMOSTAT_AP");

EEPROM.begin(512); //Initialize EEPROM

float a = read_String(10);

float b = read_String(100);

float c = read_String(150);

if (isnan(a)) {

writeString(10, 20.25);

}

if (isnan(b)) {

writeString(100, 0.25);

}

if (isnan(c)) {

writeString(150, 0.00);

}

// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally

if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

Serial.println(F("SSD1306 allocation failed"));

for(;;); // Don't proceed, loop forever

}

// Show initial display buffer contents on the screen --

// the library initializes this with an Adafruit splash screen.

display.display();

delay(2000); // Pause for 2 seconds

// Clear the buffer

display.clearDisplay();

sensorsA.begin();

pinMode(Relay, OUTPUT);

digitalWrite(Relay, HIGH);

sensorsA.requestTemperatures();

delay(750);

Serial.println(F("WiFi thermostat - Author: Martin Chlebovec"));

Serial.println("");

Serial.println(F("WiFi connected."));

Serial.println(F("IP address: "));

Serial.println(WiFi.localIP());

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(2, 2);

display.println("IP: ");

display.setCursor(22,2);

display.println(WiFi.localIP());


display.display();

server.on("/", handleRoot);

server.on("/get_data.json", handleGet);

server.on("/automat.html", handleAuto);

server.on("/manual.html", handleManual);

server.on("/RelConPn.html", handleRelConPn);

server.on("/RelConPf.html", handleRelConPf);

server.on("/action.html", HTTP_POST, handleBody);

server.begin();

}


void loop() {

if ((millis() - kase) >= 10000 || kase == 0) {

kase = millis();

TempVal = sensorsA.getTempCByIndex(0);

Serial.println();

Serial.println(F("----------------------------------------------"));

Serial.print(F("IP address of ESP8266 thermostat: "));

Serial.print(WiFi.localIP());

Serial.print(F(", for access via mDNS use http://"));

Serial.print(WiFi.localIP());

Serial.println(F("/"));

Serial.print(F("Free HEAP: "));

Serial.print(ESP.getFreeHeap());

Serial.println(F(" B"));

Serial.print(F("Actual DS18B20 temperature: "));

Serial.print(String(TempVal));

Serial.println(F(" °C"));

display.clearDisplay();

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(2, 2);

display.println("IP: ");

display.setCursor(22,2);

display.println(WiFi.localIP());

display.display();

display.setTextSize(3); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(0, 17);

display.println(String(TempVal));

display.println(" ");

display.drawRect(90, 17, 5, 5, WHITE); // put degree symbol ( ° )

display.setCursor(97, 17);

display.println("C");

display.display();

sensorsA.requestTemperatures();

SysMode = read_String(150);

if (SysMode == 0.00) {

float SetTemppoint = read_String(10);

float SetHss = read_String(100);

float minus_SetHss_TempVal = (-1 * SetHss);

float different = SetTemppoint - TempVal; //21 - 20

Serial.println(SetHss);

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(0, 45);

display.print(SetHss);

display.display();

Serial.println(SetTemppoint);

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(70, 45);

display.print(SetTemppoint);

display.display();

if (different > SetHss) {

Serial.println(F("Output ON"));

Heater = "ON";

digitalWrite(Relay, LOW);

} else if (different < minus_SetHss_TempVal) {

Serial.println(F("Output OFF"));

Heater = "OFF";

digitalWrite(Relay, HIGH);

} else {

Serial.println(F("Difference between the target and actual temperature is not above or below the hysteresis. The output status does not change."));

Serial.print(F("Actual output state: "));

Serial.println(Heater);

}

} else {

Serial.print(F("Manual operation mode is used, output status: "));

Serial.println(Heater);

}

}


if (digitalRead(Relay)==LOW){

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(0, 55);

display.print("Heater ON ");

display.display();}

else if (digitalRead(Relay)==HIGH){

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(0, 55);

display.print("Heater OFF");

display.display();}


if (SysMode==1){

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(70, 55);

display.print("Manual");

display.display();}

else if (SysMode==0){

display.setTextSize(1); // Draw 2X-scale text

display.setTextColor(SSD1306_WHITE);

display.setCursor(70, 55);

display.print("Auto ");

display.display();}


server.handleClient();


}


After a successful upload, open the Serial Monitor at a baud rate of 152000. Press the “EN/RST” button on the ESP8266 board and see the result in serial monitor.




After that Open the web browser and enter the IP address path for Monitoring and controlling the temperature controller.




Demo:








































Comentarios


bottom of page