Daniel Roman
Published © GPL3+

The smart thermostat

The IotStat is a homemade thermostat with Wifi capabilities!

BeginnerWork in progress24 hours13,063
The smart thermostat

Things used in this project

Hardware components

Arduino Mega 2560
Arduino Mega 2560
×1
Arduino Wifi Shield 101
Arduino Wifi Shield 101
×1
Temperature Sensor
Temperature Sensor
×1
Arduino Proto Shield
Arduino Proto Shield
×1
Rotary Encoder with Push-Button
Rotary Encoder with Push-Button
×1

Software apps and online services

Arduino IDE
Arduino IDE
ThingSpeak API
ThingSpeak API

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

IoTStat Block diagram

IoTStat protoshield schematic

IoTStat Protoshield

Code

IoTStat code

C/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);
}
}

Credits

Daniel Roman

Daniel Roman

1 project • 2 followers
I am a Mechanical Engineering student at the University of North Carolina at Charlotte

Comments