Project tutorial

Smart Thermostat

Connect your home heater to Internet and chat with it via Telegram!

  • 48,058 views
  • 7 comments
  • 56 respects

Components and supplies

Necessary tools and machines

3drag
3D Printer (generic)
09507 01
Soldering iron (generic)

Apps and online services

About this project

Connect to this smart thermostat by simply texting it, no need of extra dashboards or platforms.

Understanding Telegram Bots

Telegram offers a super useful set of API you can use in your projects.

You can host a bot on you Arduino board and chat with it using a simple library called Telegram Bot. You can install this library via the Library Manager within the Arduino desktop IDE, or by importing the .Zip file on the Arduino Web Editor.

You can learn everything on how to manage a Telegram Bot on the MKR1000 here. In this tutorial we will skip this step, but you will see how to implement a Telegram bot in the final code.

Time management

This thermostat allows you to program a whole week and loop it.

To do that, the thermostat makes an UDP call and uses the data received to set the Real Time Clock (RTC).

Install the RTCZero and the WiFi101 libraries and upload this sketch to test this feature.


#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>
#include <RTCZero.h>

RTCZero rtc;
WiFiUDP Udp; // A UDP instance to let us send and receive packets over UDP

// Initialize Wifi connection to the router
char ssid[] = "xxxx";             // your network SSID (name)
char pass[] = "yyyy";           // your network key

WiFiSSLClient client;
unsigned long epoch;
unsigned int localPort = 2390;      // local port to listen for UDP packets
IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets

void setup() {

  Serial.begin(115200);

  // attempt to connect to Wifi network:
  Serial.print("Connecting Wifi: ");
  Serial.println(ssid);
  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.println("WiFi connected");

  rtc.begin();
  GetCurrentTime();
}

void loop() {
  Serial.print("Unix time = ");
  Serial.println(rtc.getEpoch());

  // Print date...
  Serial.print(rtc.getDay());
  Serial.print("/");
  Serial.print(rtc.getMonth());
  Serial.print("/");
  Serial.print(rtc.getYear());
  Serial.print("\t");

  // ...and time
  print2digits(rtc.getHours());
  Serial.print(":");
  print2digits(rtc.getMinutes());
  Serial.print(":");
  print2digits(rtc.getSeconds());
  Serial.println();

  delay(1000);
}

void print2digits(int number) {
  if (number < 10) {
    Serial.print("0");
  }
  Serial.print(number);
}

void GetCurrentTime() {

  int numberOfTries = 0, maxTries = 6;
  do {
    epoch = readLinuxEpochUsingNTP();
    numberOfTries++;
  }
  while ((epoch == 0) || (numberOfTries > maxTries));

  if (numberOfTries > maxTries) {
    Serial.print("NTP unreachable!!");
    while (1);
  }
  else {
    Serial.print("Epoch received: ");
    Serial.println(epoch);
    rtc.setEpoch(epoch);
    Serial.println();
  }

}

unsigned long readLinuxEpochUsingNTP()
{
  Udp.begin(localPort);
  sendNTPpacket(timeServer); // send an NTP packet to a time server
  // wait to see if a reply is available
  delay(1000);

  if ( Udp.parsePacket() ) {
    Serial.println("NTP time received");
    // We've received a packet, read the data from it
    Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
    //the timestamp starts at byte 40 of the received packet and is four bytes,
    // or two words, long. First, esxtract the two words:

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    // combine the four bytes (two words) into a long integer
    // this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    // now convert NTP time into everyday time:
    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
    const unsigned long seventyYears = 2208988800UL;
    // subtract seventy years:
    Udp.stop();
    return (secsSince1900 - seventyYears);
  }
  else {
    Udp.stop();
    return 0;
  }
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress & address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)

  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

Saving settings

Of course you don't want your thermostat to forget its settings every time it turns off :)

To avoid this issue you can store data in the flash memory of your board by using the FlashStorage library.

In this particular case we use this feature to store a struct of 7 days and 7*24 hours, and the value of the desired temperature.

Upload this example to test this feature.


/*
  Store and retrieve an integer value in Flash memory.
  The value is increased each time the board is restarted.
  This example code is in the public domain.
  Written 30 Apr 2015 by Cristian Maglie 
*/

#include <FlashStorage.h>

// Reserve a portion of flash memory to store an "int" variable
// and call it "my_flash_store".
FlashStorage(my_flash_store, int);

// Note: the area of flash memory reserved for the variable is
// lost every time the sketch is uploaded on the board.

void setup() {
  SERIAL_PORT_MONITOR.begin(9600);

  int number;

  // Read the content of "my_flash_store" and assign it to "number"
  number = my_flash_store.read();

  // Print the current number on the serial monitor
  SERIAL_PORT_MONITOR.println(number);

  // Save into "my_flash_store" the number increased by 1 for the
  // next run of the sketch
  my_flash_store.write(number + 1);
}

void loop() {
  // Do nothing...
}

Reading values from the sensors

In this project we are using a DHT sensor that can detect humidity and temperature. This sensor has its own library, you can download it here.

Since the sketch implements a lot of functionalities we organized it in different tabs, these following snippets of code refer to the sensors.

In the Config tab we declare the sensor's class:

//#define USE_fahrenheit true  // Uncomment this to use Fahrenheit insted of Celsius

class Sensor {
  public:
      Sensor(void);
      void begin();
      bool ReadSensors();
      float GetTemp();
      float GetHumidity();
  private:
      float t;
      float f;
      float h;
};
extern Sensor DHTSensor;


In another tab we define the sensor class:

#include "DHT.h"
#include "config.h"

DHT dht(DHTPIN, DHTTYPE);

Sensor::Sensor(void) {
}

bool  Sensor::ReadSensors() {
  h = dht.readHumidity();
  t = dht.readTemperature(); // Read temperature as Celsius (the default)
  f = dht.readTemperature(true);  // Read temperature as Fahrenheit (isFahrenheit = true)
  if (isnan(h) || isnan(t) || isnan(f)) {             // Check if any reads failed and exit early (to try again).
    Serial.println("Failed to read from DHT sensor!");
    return false;
  }

  return true;
}

void Sensor::begin() {
  dht.begin();
}

float  Sensor::GetTemp() {
#ifdef USE_fahrenheit
  return f;
#else
  return t;
#endif
}

float Sensor::GetHumidity() {
  return h;
}

Hardware components and libraries

Now you can start wiring up your thermostat. Consider that the LCD display requires the GFX and the ST7735 libraries, while the DHT sensor needs the  DHT-sensor-library

Custom parts and enclosures

Thermostat.stl
Button

Schematics

Thermostat Layout
Thermofritzing

Code

Arduino Sketch

Comments

Similar projects you might like

Mini Telegraph

Project showcase by Yegor_A

  • 3,078 views
  • 4 comments
  • 20 respects

Nematoduino

Project showcase by nategri

  • 3,653 views
  • 3 comments
  • 29 respects

Alzheimer's Assistant

Project tutorial by Abdullah Sadiq

  • 4,461 views
  • 2 comments
  • 34 respects

Arduino Powered Service Elevator

Project tutorial by Lasith Ishan Premaratne

  • 3,880 views
  • 8 comments
  • 24 respects

Cubik Lamp

Project showcase by KIMbAB STUDIO

  • 1,111 views
  • 2 comments
  • 4 respects

Arduino-Powered Pellet Boiler

Project showcase by Federico Aschero

  • 440 views
  • 0 comments
  • 5 respects
Add projectSign up / Login