In the second part of this tutorial we added to our wireless thermostat the ability to interact with the user through an LCD display and switches. We can simply increase/decrease temperature using two practical switches and we can see the ambient temperature on the LCD display. We also used an AirQ 100 wireless temperature sensor to separate the Arduino from where we want to detect temperature: this allows us maximum flexibility since AirQ 100 sensor can be placed wherever we want.
We are not satisfied, however: in the Internet of Things (IoT) era there is more to do. We want to control our thermostat by the Internet. And the good news it that it’s a trivial task tanks to Arduino Ethernet shield. Let’s go
Bill of material
For this part of the tutorial we need the following material:
- One Arduino Uno.
- An Arduino Ethernet shield.
- An AirQ ShielD for Arduino Uno.
- An AirQ 305 wireless relay board.
- An AirQ 100 low-cost wireless temperature sensor.
- A character 16×2 LCD (see part two for more info about this).
- Two SPST switches.
The hardware setup
The hardware setup is almost the same of the second part of this tutorial. There are only a couple of differences:
- We obviously need the Ethernet shield and we can put it between Arduino and AirQ ShielD (we always suggest to put AirQ ShielD on the top to avoid reduction of operative distance between the shield and other AirQ Networks devices).
- Since AirQ ShielD uses pin 10 and 11 and these pins are also used by Ethernet shield, we need to rearrange them. So, using a couple of patches, and leaving those pins non inserted in the ethernet shield pin headers, we can rearrange pin 10 and 11 on pin 8 and 9 respectively, as shown in the following photo.
With these two fixes we are ready to add web functionalities to our thermostat
The code
The code isn’t too much different from the one in the previous part. We only need to add the web part. And to do this we use the excellent framework TinyWebServer by Ovidiu Predescu.
#include <SoftwareSerial.h> #include <sNET.h> #include <LiquidCrystal.h> #include <SPI.h> #include <Ethernet.h> #include <Flash.h> #include <TinyWebServer.h> float setTemp = 18.0; // This variabile sets the desired ambient temperature char blank[] = " "; // Clears a LCD line char line1[16], line2[16]; uint8_t upBTN = 6; uint8_t downBTN = 7; LiquidCrystal lcd(5, 4, 3, 2, 1, 0); sNET snet(2, 8, 9); AIRQ305 *board; AIRQ100 *sensor; // Enter a MAC address and IP address for your thermostat below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; byte ip[] = { 192, 168, 2, 177 }; boolean index_handler(TinyWebServer& web_server); boolean inc_handler(TinyWebServer& web_server); boolean dec_handler(TinyWebServer& web_server); TinyWebServer::PathHandler handlers[] = { {"/", TinyWebServer::GET, &index_handler }, {"/inc", TinyWebServer::GET, &incdec_handler }, {"/dec", TinyWebServer::GET, &incdec_handler }, {NULL}, }; TinyWebServer web = TinyWebServer(handlers, NULL); /* This is all the boilerplate code used to render home page of the web thermostat */ boolean index_handler(TinyWebServer& web_server) { web_server.send_error_code(200); web_server.send_content_type("text/html"); web_server.end_headers(); web_server << F("<html><body><h1>Ambient temperature: "); web_server << F("<font style='color:red'>"); web_server << float2char(sensor->getTEMP()); web_server << F("</font><br/>Set temperature: "); web_server << F("<font style='color:red'>"); web_server << float2char(setTemp); web_server << F("</font> <a href='inc' style='font-size:140%'>+</a>/<a href='dec' style='font-size:140%'>-</a><br/>RELAY1 status: <font style='color:red'>"); web_server << (board->getRELAY1() ? "<font style='color:green'>ON</font>" : "<font style='color:blue'>OFF</font>"); web_server << F("</font></body></html>\n"); return true; } /* /inc and /dec pages are used to increment and decrement setTemp variabile */ boolean incdec_handler(TinyWebServer& web_server) { web_server << F("HTTP/1.1 303 See Other\n"); web_server << F("Location: /"); web_server.end_headers(); if(strcmp(web_server.get_path(), "/inc") == 0) setTemp += 0.1; else setTemp -= 0.1; return true; }
In the first part of the sketch we do all the required stuff to setup the web server. We create two page handlers: index_handler() and incdec_handler(). The first handler is responsible to generate the home page of the thermostat, as shown in the following screen capture:
The incdec_handler() handles the call to /inc and /dec urls: these links allow to increment and decrement desired ambient temperature. The remaining part of the code is nothing more than the same code of the part two of this tutorial.
void lcdUpdate(char* line1, char *line2) { if(line1 != 0) { lcd.setCursor(0,0); lcd.print(blank); lcd.setCursor(0,0); lcd.print(line1); } if(line2 != 0) { lcd.setCursor(0,1); lcd.print(blank); lcd.setCursor(0,1); lcd.print(line2); } } /* Since Arduino sprintf lacks support for float conversion, this a convinient routine to convert a float to a string with a precision of 1 decimal */ char *float2char(float x) { static char str[5]; int i; i = x*10; /* 1 digit precision */ if(i> 0) sprintf(str, "%d.%d", i/10, i%10); else sprintf(str, "%d.%d", i/10, -i%10); return str; } void setup() { // Set pins to interface upBTN and downBTN pinMode(upBTN, INPUT); pinMode(downBTN, INPUT); digitalWrite(upBTN, HIGH); /* Enables pull-up resistors on both pins */ digitalWrite(downBTN, HIGH); // start the Ethernet connection and the server: Ethernet.begin(mac, ip); web.begin(); snet.begin(); lcd.begin(16, 2); sprintf(line2, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); lcdUpdate("IP Address", line2); delay(3000); /* We wait until both AIRQ 305 and AIRQ 100 are detected */ lcdUpdate("Waiting R1...", "Waiting sensor..."); while((board = (AIRQ305*)snet.getDeviceForDeviceID(5,0,1,3)) == 0) snet.processMessages(); lcdUpdate("Connected!", "Waiting sensor..."); while((sensor = (AIRQ100*)snet.getDeviceForDeviceID(101,2,1,0)) == 0) snet.processMessages(); lcdUpdate("Connected!", "Connected!"); } void loop() { /* sNET::processMessages() is responsibile to process messages coming from AirQ Networks devices and to update corresponding device object (in this example, the AIRQ305 and AIRQ100 objects). User code should call this method as soon as possible and continuosly */ snet.processMessages(); delay(150); //A little bit of debouncing web.process(); if(!digitalRead(upBTN)) setTemp += 0.1; if(!digitalRead(downBTN)) setTemp -= 0.1; sprintf(line1, "Temp: %s", float2char(sensor->getTEMP())); sprintf(line2, "SET:%s - R1:%d", float2char(setTemp), board->getRELAY1()); lcdUpdate(line1, line2); if(sensor->getTEMP() > setTemp) /* Temperature raised too much: turn off bolier */ board->setRELAY1(OFF); else if(sensor->getTEMP() < setTemp) /* Temperature decreased too much: turn on bolier */ board->setRELAY1(ON, false); }
Different lines are highlighted and it’s really simple to see that those lines are only related to the web part. If you are not familiar to TinyWebServer we suggest to take a look to the SimpleWebServer example.
The following video shows the thermostat in action
What’s next?
Our thermostat is still really minimal. There are many improvements that can be added to make it more robust and complete. For example, it could be really useful to add a way to put it in manual mode. This could simply done using a couple of switches connected to the inputs of the AirQ 305 I/O board. Another important feature is the ability to program it on time basis. To do this, a RTC should be used. Moreover, the web interface is still too bare and it could be improved with other functionalities. But now it’s up to you This tutorial gives all the needed info to setup a wireless and web oriented thermostat using Arduino, for a total cost of less than 130€ (take a look to wireless/web oriented thermostat around and you’ll discover that they are much more expensive). Moreover, this thermostat can be adapted to our needs, and it could be expanded to interface other temperature sensors and control boards. So, your imagination starts now! Enjoy