Indoor temperature gauge, Part 2: The Server Side


It’s here! Part two of our development project for the creation of an indoor temperature gauge based on Arduino! Inside the previous article we covered the topic of creating the interface in terms of design and visual functionalities. Now, however, it’s time to have a deeper look over the server side code running on the Arduino microcontroller, as well as provide our already implemented interface with a mechanism to communicate with this server and constantly receive a fresh temperature value from the sensor, attached to the Arduino.

Yet again, how is this article organized?

I decided to split the article in two major parts, reflecting the two corresponding functionalities to be done in our development project – the Arduino server and the enhancements to our interface. The names say everything – the first part will cover the whole microcontroller code base, while the second will reveal what extensions and modifications need to be applied to the interface so that it can make use of the server. Keep in mind, however, that if you are a new to Arduino, we won’t clarify many of the basics here (at least not thoroughly), so some parts of this article may, if the case is such, seem vague to you.

Prerequisites

There are a lot of them, actually… Here is a simplified list:

  1. Since we are creating a temperature gauge based on Arduino, you need an Arduino microcontroller (unsurprisingly) with an additional Ethernet shield and a temperature sensor. In my case I use an Arduino Leonardo with a non-Arduino Ethernet shield (i.e. compatible shield which is produced by some other unknown manufacturer) and a DHT-11 temperature and humidity sensor (we make use of the temperature measuring functionality only).
  2. Furthermore, it is required that you install Arduino IDE so that you can use, modify and upload the server code on the Arduino.
  3. Finally, you need a router at your home, so that you can connect the Arduino microcontroller to the Internet through it (using an ethernet cable which is plugged to the ethernet shield of the Arduino, on the one side, and to one of the LAN ports of the router, on the other).

Technical schematics

Now, we have to ensure that the temperature sensor is correctly wired to the Arduino, while the microcontroller itslef is connected to the Internet and is powered up (for the last two you need the mentioned ethernet cable connected to your home router, as well as a micro-USB phone charger). Considering the temperature sensor, we will take the DHT-11 into account, since it is a really good choice due to its low price, high accuracy (deviation is plus/minus 1 degree Centigrade) and low operating voltage (it can operate in the range from 3 to 5 volts). So, in terms of wiring, we need to connect the sensor’s pins (respecting what pin is for what) to the Arduino’s 3.3 volt pin, one of the ground pins and an analog signal pin of our choice (since this sensor transmits data through the analog microcontroller inputs) – for the last one I have chosen analog pin 4 (A4). Take a careful look at the diagram below before doing the wiring (especially if you are using the same kind of sensor):

Wiring DHT-11 sensor to Arduino

Wiring of the DHT-11 sensor to Arduino

 

The Arduino server itself

All components completely wired up

All components completely wired up

Right, we have all wires placed where they have to be, Internet connection and power are present, we’re ready to continue ahead! We need to write the code which will make our Arduino act as a web server, sending temperature values. But before we come to the real part, we need to do something else – find out the Arduino’s  IP adress in our local network. To do that, we need to go in the Arduino IDE, select File > Examples > Ethernet and open the DhcpAddressPrinter sketch (comes together with the installation of the Arduino development environment). After uploading the sketch on the Arduino, while still in the IDE, go to Tools > Serial Monitor (or hit Ctrl + Shift + M if using Windows) and you will see Arduino having printed its DHCP address, or the internal local network address we need. In my case, it is 192.168.0.101, but it can be anything, depending on your router. We need this address, since the Arduino (as a server) will effectively run on it and, from inside the interface, we are going to preform asynchronous calls to this address to invoke the server receive back the temperature data. Furthermore, we also need the MAC address of the Arduino which, in case you are using Windows, can be retrieved by typing arp -a and ipconfig -all in the command prompt (by having a deeper look in the results of these two commands, you won’t have trouble finding the MAC address of the microcontroller).

So far, so good, we know the IP address of our Arduino. Now it’s time to make it behave like a server!

The whole snippets considering the server side comming up will be placed in a single Arduino sketch which is to be uploaded to the microcontroller. In the very begining, we need to add the libraries used for communication with the ethernet shield and temperature sensor of the Arduino:

#include <SPI.h>
#include <Ethernet.h>
#include <dht.h>

Further ahead, we need to declare global variables which we are going to use for invoking the ethernet shield and the temperature sensor. Namely, we declare the MAC and IP addresses of the microcontroller, then we initialize a server with the IP address and a port of our choice (I have chosen 8081) and finally we initialize the DHT-11 temperature sensor library.

byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; // MAC address of the Arduino
IPAddress ip(192,168,0,101); //IP address of the Arduino

// Initialization of the Ethernet server library
// with the IP address and a port of our choice
EthernetServer server(8081);

//DHT11 temperature sensor library initialization
dht DHT;

//Definition of the port on which the

//temperature senros will be sending data
#define DHT11_PIN A4

Now, we have come to the setup() method (present in every Arduino sketch) where we may put code to be run only once. In our case, the setup() method is the perfect place to start the server and notify on which address it is running in the serial console of the Arduino IDE:

void setup() {
    // Open serial communications and wait for port to open:
    Serial.begin(9600);

    while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
    }

    // Start the Ethernet connection and the server:
    Ethernet.begin(mac, ip);
    server.begin();
    Serial.print("server is at ");
    Serial.println(Ethernet.localIP());
}

Finally, we have reached the point for implementation of the loop() function (also present in every Arduino sketch) where we may put code which is looped forever by the microcontroller. In our case, inside every loop, we want to implement the logic for temperature value sending. What we actually do in the loop() method is first look for incoming clients which want to connet to the server. Then, if there is a client connected and it is available for sending (writing) data to it, we begin reading the data that the client is carrying character by character and apply the following logic (simply explained): if we have received a newline character and the whole line is blank, the HTTP request has ended and we can send back the response; if, however, we have got a carriage return or only a newline character, then the line is not blank, we still cannot send the response. Did you get mixed up? Have a look at the code below, it speaks for itself. What is to mention here as well is that, for the HTTP response, we use the client.print() and client.println() methods to form the response headers and body, whilst attaching the temperature value to the body (we do this in a DHT-library-specific way, once again check the example).

void loop() {
    // Listen for incoming clients
    EthernetClient client = server.available();

    if (client) {
        Serial.println("new client");
        // An http request ends with a blank line
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {
                char c = client.read();
                Serial.write(c);
                // If you've gotten to the end of the line (received a newline
                // character) and the line is blank, the http request has ended,
                // so you can send a reply
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    client.println("Content-Type: text/html");
                    client.println("Connection: close"); // On complete response, connection will be closed
                    // We need the header below if we run our interface html file locally (file:///)
                    client.println("Access-Control-Allow-Origin: *");
                    client.println();

                    // Output the temperature value
                    int checkTemp = DHT.read11(DHT11_PIN);
                    int tempValue = DHT.temperature;
                    String temperature = (String) tempValue;
                    client.print(temperature);

                    break;
                }

                if (c == '\n') {
                    // You're starting a new line
                    currentLineIsBlank = true;
                } else if (c != '\r') {
                    // You've gotten a character on the current line
                    currentLineIsBlank = false;
                }
            }
        }
        // Give the web browser time to receive the data
        delay(1);
        // Close the connection:
        client.stop();
        Serial.println("client disconnected");
    }
}

That’s it, Arduino server is ready and, with the current settings for my local network, it can be invoked through http://192.168.0.101:8081. Now we have come to…

The enhancements to the interface

Before talking about the interface, please have another look at the first article considering the interface, so that you know what we are discussing from this point on. Everything that is to be covered later is situated ONLY in the <script> tag with the main JavaScript logic from the first article, please keep this in mind.

The enhancements to the script from the first article are, actually, very small. Additionally, we do one simple thing – “ping” the Arduino server every second to update the temperature. How is this achieved?

Firstly, at the begining of our front-end logic script, we need to declare a variable holding the address of our server. In my local network case, it is the following (as mentioned before):

var ARDUINO_SERVER_URL = 'http://192.168.0.101:8081';

Further ahead, we declare a function called readTemperature(). Inside it, we do an asynchronous AJAX GET request to the server and, if the request is successful and we have got response, report the temperature in the console and change the temperature value in the markup (the element with ID #temp-value). If, however, the response fails (e.g. the server is down, the Arduino is turned off, etc.) we set the temperature to 0 (as a default value).

function readTemperature() {
    $.ajax({
        type: 'GET',
        url: ARDUINO_SERVER_URL
    }).success(function(temperature) {
        if(temperature) {
            $('#temp-value').html(temperature);
            console.log('Received temperature: ' + temperature + ' C');
        }
    }).error(function() {
        $('#temp-value').html('0');
    });
}

The last thing we need is make our script invoke the readTemperature() method every second in order to have our temperature regularly updated. We can achieve that like this:

// Repeatedly call readTemperature() every second (1000 ms)
window.setInterval(function(){
    readTemperature();
}, 1000);

The whole main front-end logic script then will look like this:

<script>
    var ARDUINO_SERVER_URL = 'http://192.168.0.101:8081';

    $('#temp-value').bind('DOMSubtreeModified',function(){
        adaptBackground();
    });

    $('#temp-value').on('change',function(){
        adaptBackground();
    });

    window.setInterval(function(){
        readTemperature();
    }, 1000);

    function adaptBackground() {
        var temp = $('#temp-value').html();
        var hue = 200 - (parseInt(temp) * 5);
        $('body').css('background-color', 'hsl(' + hue + ', 60%, 65%)');
    }

    function readTemperature() {
       $.ajax({
            type: 'GET',
            url: ARDUINO_SERVER_URL
        }).success(function(temperature) {
            if(temperature) {
                $('#temp-value').html(temperature);
                console.log('Received temperature: ' + temperature + ' C');
            }
        }).error(function() {
            $('#temp-value').html('0');
        });
    }
</script>

That’s it, our simple project is complete! We have got our cool temperature gauge! Hope you have enjoyed the two articles and are keen to try this yourself. Wish you happy coding!

Alex


Leave a comment

Your email address will not be published. Required fields are marked *