Project in progress

The smart thermostat © GPL3+

The IotStat is a homemade thermostat with Wifi capabilities!

  • 8,168 views
  • 1 comment
  • 12 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

A poor Midterm grade and an engineer's desire for a "smart" thermostat lead to the creation of The IoTStat.  This overly sized thermostat runs on code from the Arduino 1.6.8 software on an Arduino Mega 2560.  It not only has a WiFi 101 shield and a temperature sensor but it also has plenty of potential. 

My MEGR 3171 professor at UNCC gave us the opportunity to monitor and/or control a sensor through the internet of things.  I took this opportunity to contact a friend of mine who is an engineer at IBM for his assistance in creating a thermostat that can be monitored from the internet.  His guidance and assistance were greatly appreciated as I am new to projects such as this one.

As previously stated, the IoTStat runs on an Arduino Mega with a wifi shield connected on top of it.  On top of the wifi shield is the prototype shield.  The prototype shield has the temperature sensor, rotary encoder,  and the ports for the wall connected to it.  The purpose of this shield is to provide a board that connects the Arduino Mega to the previously stated components.  

Temperature readings are taken from the sensor and relayed to the Arduino.  This temperature is compared to the desired temperature and a decision is made to turn on the A/C, the heat, or neither in order to reach or maintain the desired temperature.  One added parameter is a defined "season" to prevent either the A/C or heat to come on depending on the season.  The two seasons are the "Heating" and "Cooling" seasons.  During the heating season the A/C will never turn on no matter the current and desired temperatures and vice versa for cooling season.  This is useful as we do not want the A/C to come on when the heater accidentally raises the current temperature slightly above the desired temperature.  A demonstration of the IoTStat in action can be seen below:

The IoTStat in action

Although the rotary encoder is functioning properly there is no way to tell what season it is or what the current/desired temperatures are by simply looking at the IoTStat.  That is why a display will soon be connected to show current/desired temperatures and also the current season of the system.  Although we cannot see these settings on the IoTStat itself we can see the current and desired temperatures of the system through ThingSpeak.com.  Thanks to the internet of things we can monitor our thermostat from the comfort of our bed, workplace, or even bathroom.  The link to the IoTStat channel can be seen below:

https://thingspeak.com/channels/109452

The IoTStat is a functioning thermostat and it can be monitored online but it is not finished.  A physical display similar to one on a regular thermostat is still needed to reduce the burden of the ThingSpeak channel.  A twin sister is soon to be born as well for the downstairs unit.  These sisters will be in contact with eachother through ThingSpeak to optimize temperature control throughout the household.  Any changes and additions to the IoTStat and its twin sister will be uploaded here!

This project was done as an extra credit assignment for MEGR 3171 at UNCC.

Code

IoTStat codeC/C++
This code runs the IoTStat, connects it to the internet, and sends data to ThingSpeak.
/*
  Web Enabled Thermostat (IoTstat)

  A simple ThingSpeak feed that shows the thermostat values:
  - Desired Temperature(F)
  - Current temperature(F)
*/

//include the built-in libraries:
#include <Wire.h>
#include <SPI.h>

/* include the following add-on libraries, each of these must be downloaded, and unzipped to the following directory:
       C:\Users\<user-name>\Documents\Arduino\libraries
*/
#include <WiFi101.h>

/* Circuit:
   WiFi101 shield attached
   Prototype Shield with the following pin connections:
*/

int VTemp = 0;              // A0 TMP36 Temperature sensor
int HeatOn = 10;            // heat output digital pin
int CoolOn = 11;            // cool output digital pin
int HeatingCoolingBar = 9;  // season input digital pin
int encoder0PinA = 2;		// rotary encoder pin A
int encoder0PinB = 3;       // rotary encoder pin B
int RotaryTopHat = 8;       // rotary encoder top hat switch

//some temperature variables
int maxTemp = 80;
int minTemp = 50;
int counter = 0;
int flag;
volatile unsigned int desiredTemperature = (maxTemp + minTemp) / 2;
volatile unsigned int lastDesiredTemperature = desiredTemperature;

//thermostat variables
int desiredTempF =  72; // hardcoded for now
int prevTemp = 72; // hardcoded for now
int currentTempF =  0;  // variable to store the current temperature value

//SEASONS
#define HEATING_SEASON 1
#define COOLING_SEASON 0
int season; 

//Wifi Network Access Info
char ssid[] = "TG1672G02";      // your network SSID (name)
char pass[] = "TG1672G159702";   // your network password
int keyIndex = 0;
int status = WL_IDLE_STATUS;


// ThingSpeak variables
char thingSpeakAddress[] = "184.106.153.149";	//char thingSpeakAddress[] = "api.thingspeak.com";
String APIKey = "P452GINXXH42AAET";             // enter your channel's Write API Key
const int updateThingSpeakInterval = 20 * 1000; // 20 second interval at which to update ThingSpeak
long lastConnectionTime = 0;
boolean lastConnected = false;

/*
   updateThingSpeak() is called from within loop()
*/
void updateThingSpeak(String tsData) {
  // Initialize Arduino Ethernet Client
  WiFiClient client;
  if (client.connect(thingSpeakAddress, 80)) {
    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: " + APIKey + "\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(tsData.length());
    client.print("\n\n");
    client.print(tsData);
    lastConnectionTime = millis();

    if (client.connected()) {
      Serial.println("Connecting to ThingSpeak...");
      // Print Update Response to Serial Monitor
      if (client.available()) {
        char c;
        do {
          char c = client.read();
          Serial.print(c);
        } while (c != 0);
      }
      Serial.println();
    }
    // Disconnect from ThingSpeak
    client.stop();
  }
}
/*
   printWifiStatus() is called from setup() and sends information about the Wifi connection to the serial monitor
*/
void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
  IPAddress gateway = WiFi.gatewayIP();
  Serial.print("Gateway Address: ");
  Serial.println(gateway);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}
/*
   doEncoder() is attached as an interrupt handler to the rotary encoder pins and is executed whenever
   the user adjusts the control
*/
void doEncoder() { 
  /* If pinA and pinB are both high or both low, it is spinning
     forward. If they're different, it's going backward.

     For more information on speeding up this process, see
     [Reference/PortManipulation], specifically the PIND register.
  */
  delay(100);
  if (digitalRead(encoder0PinA) == digitalRead(encoder0PinB)) {
        flag++;
        counter++;
  } else {
        flag--;
        counter++;
  }
 
}

/*
   setup() - runs once when the Arduino is powered up
   make sure to match the serial monitor bit rate to the value specified in the Serial.begin(...); call below
*/
void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("IoTStat is initializing...");

  //configure the Arduino pins
  pinMode(HeatOn, OUTPUT);  				// sets the digital pin as output pin
  pinMode(CoolOn, OUTPUT);  				// sets the digital pin as output pin
  pinMode(HeatingCoolingBar, INPUT_PULLUP);	// sets the digital pin as input pin
  pinMode(RotaryTopHat, INPUT_PULLUP); //Sets the digital pin as input pin
  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH);       // turn on pullup resistor
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);       // turn on pullup resistor

  //the doEncoder() interrupt function is called whenever the rotary encoder is turned
  attachInterrupt(digitalPinToInterrupt(3), doEncoder, CHANGE);

  // check for the presence of the WiFi101 shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // connect to the Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Please wait, attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  } 

  // you're connected now, so print out the status:
  printWifiStatus();

}

/*
   loop() executes continuously
*/
void loop() {
  if(digitalRead(RotaryTopHat)==0) {
       int th_down_time = millis();
       do {
         //stay here as long as the top hat is depressed
         //if down for more than 2000ms change the season
       } while(digitalRead(RotaryTopHat)==0);
       if((millis()-th_down_time)>2000) {
         if(season==COOLING_SEASON) {
           season=HEATING_SEASON;
           Serial.println("\nHEATING SEASON");
         } else {
           season=COOLING_SEASON;
           Serial.println("\nCOOLING SEASON");
         }
       }
    }


  //Send current time HH:MM:SS to serial monitor
  //echoRtcTime(rtc.now());

  //Show status of HEAT/COOL switch
  //if (digitalRead(HeatingCoolingBar) == 0)
   // Serial.println("\nCOOLING SEASON");
  //else
   // Serial.println("\nHEATING SEASON");

  //perform temperature sensor math
  int tempA2D = analogRead(VTemp);
  int tempSensorMillivolts = 4.8828 * analogRead(VTemp);
  int currentTempC = (tempSensorMillivolts - 500) / 10;
  currentTempF = (9 * currentTempC) / 5 + 32;

  //Send desired temperature (F( to serial monitor
  if (flag > 0){
  if (counter>0 && counter<6) {
        prevTemp = prevTemp + 1;
  } 
  if ((counter>=6) && (counter<12)){
        prevTemp = prevTemp + 2;
  }
  if ((counter>=12) && (counter<18)) {
        prevTemp = prevTemp + 3;     
  }
  if ((counter>=18) && (counter<24)) {
        prevTemp = prevTemp + 4;
  }
  if (counter>24) {
        prevTemp = prevTemp + 5;
  }
  }
  if (flag < 0){
  if (counter>0 && counter<6) {
        prevTemp = prevTemp - 1;
  } 
  if ((counter>=6) && (counter<12)){
        prevTemp = prevTemp - 2;
  }
  if ((counter>=12) && (counter<18)) {
        prevTemp = prevTemp - 3;     
  }
  if ((counter>=18) && (counter<24)) {
        prevTemp = prevTemp - 4;
  }
  if (counter>24) {
        prevTemp = prevTemp - 5;
  }
  }
  desiredTempF = prevTemp;
  if (desiredTempF > maxTemp){
    desiredTempF = maxTemp;
  }
  if (desiredTempF < minTemp){
    desiredTempF = minTemp;
  }
  counter = 0;
  Serial.print("desiredTemp="); Serial.println(desiredTempF);
  Serial.print("currentTemp="); Serial.println(currentTempF);
  flag = 0;
  // Update ThingSpeak
  if ((millis() - lastConnectionTime) > updateThingSpeakInterval) {
    //format the temperatures to send to ThingSpeak
    String desiredTempMsg = String(desiredTempF);
    String currentTempMsg = String(currentTempF);
    updateThingSpeak("field1=" + desiredTempMsg + "&field2=" + currentTempMsg);
    Serial.println("ThingSpeak updated");
  }
  //lastConnected = client.connected();
  lastDesiredTemperature = desiredTemperature;
  delay(3000);

  if((season==COOLING_SEASON)&&(currentTempF>desiredTempF)){
  digitalWrite(CoolOn,1);//turn on the air conditioning
  //digitalWrite(HeatOn,0);
  Serial.println("Air Conditioner on");
} else if((season==HEATING_SEASON)&&(currentTempF<desiredTempF)){
  digitalWrite(HeatOn,1);  //turn on the heating
 // digitalWrite(CoolOn,0);
  Serial.println("Heat on");
} else { 
  digitalWrite(CoolOn,0);//turn off the air conditioning
  digitalWrite(HeatOn,0);//turn off the heat
  delay(3000);
}
}

Schematics

IoTStat Block diagram
IoTStat protoshield schematic
IoTStat Protoshield

Comments

Author

1121
Daniel Roman
  • 1 project
  • 2 followers

Published on

May 2, 2016

Members who respect this project

Default1112DefaultDefault12308358 10153120173432391 6417187800241805617 n34847 405141658588 2169074 nDefaultDefault

and 4 others

See similar projects
you might like

Similar projects you might like

Night Light Assistant

Project tutorial by Gabriele Fugazzi

  • 1,033 views
  • 4 comments
  • 8 respects

Smart Energy Saver for Your Home

Project tutorial by Dhairya Parikh

  • 3,529 views
  • 8 comments
  • 12 respects

A Geiger Counter Simulator

Project tutorial by organtin

  • 1,326 views
  • 1 comment
  • 7 respects

Twilight Switch With Levels

Project in progress by Rafa Salvador

  • 1,159 views
  • 1 comment
  • 5 respects

Arduino MKR DIN Rail Mount

Project showcase by hwhardsoft

  • 1,052 views
  • 0 comments
  • 4 respects

Simple Water Quality Analysis

Project showcase by Wen-Liang Lin

  • 7,373 views
  • 5 comments
  • 10 respects
Add projectSign up / Login