Home Heat Hub

CHAPTER 3 – IMPLEMENTATION OF THE HOME HEAT HUB

3.1 Introduction

Implementing all of the required functions of the Home Heat Hub proved troublesome with regards to
memory capacity of the Nano MCU.
The memory saving techniques that were attempted:
Library Skimming – modifying libraries to remove unused functions (time consuming process)
Remove I2C – reverting back to a 4 data line LCD configuration as the I2C Library (Wire.h) is very
large.
Variable Management – where possible, changed int to short or used Booleans.
Function Overview – Created functions to handle common processes. Removed humidity
checking as it is not essential.
The resulting memory consumption was reduced to 77% which did not leave enough dynamic
memory for local variables to be populated. Further memory saving solutions should be investigated.

3.2 Software Interface

Due to memory limitations the current status of the project is split into two separate software
configurations; Manual Control and Wi-Fi Control.
Manual Control (program space used = 41%, dynamic memory = 24%) includes an LCD in I2C
configuration, 4 menu control buttons, DHT22 Temperature Sensing and Relay Control.
Wi-Fi Control (program space used = 55%, dynamic memory = 63%) sacrifices the memory heavy LCD
and I2C libraries to allow for sending and receiving data via the ESP8266 module.

3.2.1 Manual Control

The Manual Control script is quite large due to extensive coding for the menu system.
Libraries included:
DHT.h – Used for reading sensor values of the DHT22 Temperature Sensor.
Wire.h – I2C Library.
LiquidCrystal_I2C.h – LCD Library with I2C functions.

3.2.1.1 Code Listing

#define I2C_ADDR 0x27 // I2C Device Address of LCD
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
#define heatRelay 6
LiquidCrystal_I2C
lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin,BACKLIGHT_PIN,POSITIVE);
// Data pin connected to AM2302
#define DHTPIN 7
#define DHTTYPE DHT22 // DHT 22 (AM2302)
DHT dht(DHTPIN, DHTTYPE);
const int ledRed = 13;
const int buttons = A0;
// setup switch & lcd state variables
int n=1;
int a=0;
int lcdState = 0;
int heatRelayState = 0;
int ledRedState = 0;
// setup menu state variables
int currentMenuItem = 0;
int lastState = 0;
int menuBase = 0;
// initial variables for temp setpoint & temp sensor
float tempSetpoint = 10.0;
float t = 0;
// define constants for max and min temp setpoints
const int MAXTEMP = 30;
const float MINTEMP = 10.5;
// for using millis() to carry out sensor reads without hanging rest of code
unsigned long interval = 6000; // the time we need to wait (the DHT22 sensor is limited to 2 seconds
per request)
unsigned long previousMillis = 0; // millis() returns an unsigned long.
// using millis() again to determine lcd screen on time
unsigned long LCD_LIGHT_ON_TIME = 10000;
unsigned int currentLcdLightOnTime = 0;
unsigned long lcdLightOn_StartMillis;
void setup() {
pinMode(A0, INPUT_PULLUP);
attachInterrupt(A0, mainMenu, FALLING);
// set up LCD columns and rows
lcd.begin(16, 2);
lcd.clear ();
lcd.print(" Home Heat Hub");
lcd.setCursor(0,1);
lcd.print("Initialising...");
// start temperature sensing using DHT library
dht.begin();
pinMode(heatRelay, OUTPUT);
pinMode(ledRed, OUTPUT);
// set heating relay off by pulling the input high
digitalWrite(heatRelay, HIGH);
lcd.setBacklight(HIGH);
lcdState = 1;
// start timer for LCD on time
lcdLightOn_StartMillis = millis();
currentLcdLightOnTime = 0;
}
void loop() {
mainMenu();
// Utilising the millis() function to timeout the lcd display
If (lcdState != 0){
currentLcdLightOnTime = millis() - lcdLightOn_StartMillis;
if(currentLcdLightOnTime > LCD_LIGHT_ON_TIME){
lcd.setBacklight(LOW);
lcdState = 0;
}}
}
void clearPrintTitle() {
lcd.clear();
lcd.setCursor(1,0);
lcd.print("Home Heat Hub");
lcd.setCursor(0,1);
}

3.2.1.2 HEATING FUNCTIONS

void toggleHeat(){
digitalWrite(heatRelay, !digitalRead(heatRelay));
delay(500);
if ((unsigned long)(millis() - previousMillis) >= interval) {
previousMillis = millis();
float h = dht.readHumidity();
float t = dht.readTemperature();
char buffer[10];
String tempC = dtostrf(t, 4, 1, buffer);
if (menuBase == 0) {
clearPrintTitle();
lcd.setCursor(5,1);
lcd.print(t,1);
lcd.print(F("'C"));}}
}
void tempControl(float x){
clearPrintTitle();
lcd.print("New Temp: ");
lcd.print(x,1);
delay(2000);
heatControl(x);
clearPrintTitle();
mainMenu();
}
void heatControl(float x){
//float t = 0;
int heatAuto = 1;
while (heatAuto == 1){
// check current temperature
h = dht.readHumidity();
t = dht.readTemperature();
//light red led to indicate heating in auto control
digitalWrite(ledRed, HIGH);
// turn on heating if current temp is less or equal to set temp
if (t <= x){ digitalWrite(heatRelay, LOW); } else if (t > x){
digitalWrite(heatRelay, HIGH);
}
// delay for the temp sensor
delay(3000);
clearPrintTitle();
lcd.print(t,1);
lcd.print("'C AUTO ");
lcd.print(x,1);
a=readButtons();
// hold cancel switch to exit out of auto heat control
if (a == 4){
digitalWrite(ledRed, LOW);
mainMenu();
break;
}
if(lcdState != 0){
currentLcdLightOnTime = millis() - lcdLightOn_StartMillis;
if(currentLcdLightOnTime > LCD_LIGHT_ON_TIME){
lcd.setBacklight(LOW);
lcdState = 0;
}}
}
}
void changeSetpoint(){
clearPrintTitle();
lcd.setCursor(0,0);
lcd.print("SET TEMPERATURE");
int thisLoop = 1;
while (thisLoop == 1){
lcd.clear();
lcd.setCursor(6,1);
lcd.print(tempSetpoint,1);
delay(100);
a=readButtons();
if (a == 2 && tempSetpoint < MAXTEMP){ tempSetpoint = tempSetpoint +0.5; delay(200); } if (a == 3 && tempSetpoint > MINTEMP){
tempSetpoint = tempSetpoint -1;
delay(200);
}
if (a == 1){
lcd.setCursor(0,1);
lcd.print("SETTING NEW TEMP");
delay(20);
thisLoop = 0;
tempControl(tempSetpoint);
break;
}
if (a == 4){
lcd.setCursor(0,1);
lcd.print("CANCELLED ");
delay(200);
thisLoop = 0;
mainMenu();
break;
}
}
}

3.2.1.3 MENU SYSTEM

int readButtons(){
// returns the button number pressed, or zero for none pressed
int b,c = 0;
c=analogRead(buttons); // get the analog value
if (c>1000)
{
b=0; // buttons have not been pressed
}
else if (c < 30){
b=1; // button 1 pressed
lcd.setBacklight(HIGH);
lcdState = 1;
lcdLightOn_StartMillis = millis();
currentLcdLightOnTime = 0;
delay(200);
}
else if (c < 50 && c > 30){
b=2; // button 2 pressed
lcd.setBacklight(HIGH);
lcdState = 1;
lcdLightOn_StartMillis = millis();
currentLcdLightOnTime = 0;
delay(200);
}
else if (c > 50 && c < 80){ b=3; // button 3 pressed lcd.setBacklight(HIGH); lcdState = 1; lcdLightOn_StartMillis = millis(); currentLcdLightOnTime = 0; delay(200); } else if (c > 80 && c < 100){ b=4; // button 4 pressed lcd.setBacklight(HIGH); lcdState = 1; lcdLightOn_StartMillis = millis(); currentLcdLightOnTime = 0; delay(200); clearPrintTitle(); menuBase = 0; mainMenu(); } return b; } void mainMenu() { int state = 0; //lcdState = digitalRead(lcdOn); heatRelayState = digitalRead(heatRelay); a=readButtons(); if ((unsigned long)(millis() - previousMillis) >= interval) {
previousMillis = millis();
float h = dht.readHumidity();
float t = dht.readTemperature();
char buffer[10];
String tempC = dtostrf(t, 4, 1, buffer);
if (menuBase == 0) {
clearPrintTitle();
lcd.setCursor(5,1);
lcd.print(t,1);
lcd.print(F("'C"));
}
}
lcd.setCursor(0,0);
if (a == 1) {
state = 3;
}
else if (a == 2) {
state = 1;
}
else if (a == 3) {
state = 2;
}
else if (a == 4) {
state = 4;
menuBase = 0;
mainMenu();
}
if (currentMenuItem < 0 || currentMenuItem > 4) {
currentMenuItem = 0;
}
if (state != lastState) {
if (state == 1) {
currentMenuItem = currentMenuItem -1;
displayMenu(currentMenuItem);
}
else if (state == 2) {
currentMenuItem = currentMenuItem +1;
displayMenu(currentMenuItem);
}
else if (state == 3) {
selectMenu(currentMenuItem);
}
else if (state == 4) {
selectMenu(3);
}
lastState = state;
}
delay(5);
}
void displayMenu(int x) {
switch (x) {
case 1:
clearPrintTitle();
lcd.print ("> Toggle Heating");
menuBase = 1;
break;
case 2:
clearPrintTitle();
lcd.print ("> Change Temp");
menuBase = 1;
break;
case 3:
clearPrintTitle();
lcd.print ("EXIT");
menuBase = 1;
break;
}
}
void selectMenu(int x) {
switch (x) {
case 1:
clearPrintTitle();
if (digitalRead(heatRelay) == LOW){
lcd.print ("OFF");
}
else{
lcd.print("ON");
}
toggleHeat();
delay(1000);
menuBase = 0;
//mainMenu();
break;
case 2:
delay(400);
changeSetpoint();
clearPrintTitle();
menuBase = 0;
break;
case 3:
clearPrintTitle();
menuBase = 0;
mainMenu();
break;
}
}

3.2.2 Wi-Fi Control

The final Wi-Fi Control code relies upon software and libraries written by Igor Jarc of EasyIoT.
The EasyIoT library contains a configuration file Esp8266EasyIoTEspConfig.h which must be preconfigured
with the network SSID, password, server IP address and port number.
Libraries included:
Esp8266EasyIoT.h – Library used to communicate with the EasyIoT web server
SoftwareSerial.h – Soft Serial used to communicate with the ESP
DHT.h – DHT Sensor Library

3.2.2.1 Code Listing

#define RELAY_1 6 // Nano Digital I/O pin number for relay
#define RELAY_ON 0 // GPIO value to write to turn on relay
#define RELAY_OFF 1 // GPIO value to write to turn off relay
#define CHILD_ID_HUM 0 // Node number for humidity reading
#define CHILD_ID_TEMP 1 // Node number for temperature reading
#define HUMIDITY_SENSOR_DIGITAL_PIN 7 // Nano Digital I/O pin attached to DHT22 Sensor
#define DHTTYPE DHT22
Esp8266EasyIoT esp;
SoftwareSerial serialEsp(2, 3); // Setup Digital pins 2 & 3 for serial communication with ESP
DHT dht(HUMIDITY_SENSOR_DIGITAL_PIN, DHTTYPE);
float t = 0;
float h = 0;
float lastTemp;
float lastHum;
Esp8266EasyIoTMsg msgHum(CHILD_ID_HUM, V_HUM);
Esp8266EasyIoTMsg msgTemp(CHILD_ID_TEMP, V_TEMP);
void setup()
{
serialEsp.begin(9600);
esp.begin(incomingMessage, 3, &serialEsp, &Serial);
dht.begin();
pinMode(RELAY_1, OUTPUT);
digitalWrite(RELAY_1, HIGH);
esp.present(CHILD_ID_HUM, S_HUM);
esp.present(CHILD_ID_TEMP, S_TEMP);
esp.present(3, S_DIGITAL_OUTPUT);
}
void loop()
{
while(!esp.process());
delay(3000);
while(!esp.process());
t = dht.readTemperature();
if (t != lastTemp) {
lastTemp = t;
esp.send(msgTemp.set(t, 1));
}
h = dht.readHumidity();
if (h != lastHum) {
lastHum = h;
esp.send(msgHum.set(h, 1));
}
}
void incomingMessage(const Esp8266EasyIoTMsg &message) {
// Check for message coming from ESP
if (message.type==V_DIGITAL_VALUE) {
// Toggle heating relay
digitalWrite(message.sensor-3+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
}
}

retro

Author: Brian Lawes

A lover of how things work. Currently diving deep into the world of ServiceNow. Implementing Security Incident Response, Vulnerability Response, Threat Intelligence and developing cutting edge SecOps integrations. BEng(Hons) Computer Security & Forensics degree at Edinburgh Napier University. A Marine Mechanic to trade, also specialised in electrical/mechanical repair & maintenance.

Leave a Reply