Thursday 16 June 2016

Radpi #3: temperature

Once I could control the boiler, I could turn my attention to reading and storing the temperature coming from the various Raspberry pis in the house.

I bought two different kinds of temperature sensors for the pis: the DS18B20 and the DHT22. The DS18B20 has the advantage of being waterproof (so usable outside) and the DHT22 also provides humidity readings. I have used the DHT22 on one of the Raspbery pis, but the humidity being irrelevant to my goal and the DHT being more complicated, I used the DS18B20 on most of the pis. I'll only consider that one here.

The DS18B20 sensor is really easy to use. All you need is a GPIO connector, a resistor, and a soldering iron. There are good tutorials around so I'll only summarise that part here.

First, link the yellow and red wires with a 10k resistor to create a pull-up circuit as shown below.


Then solder to the GPIO connector as shown below (for the DHT22 which already containted the resistor).


The hardware bit is now done. Plug in and switch the pi on.

On recent kernels (most likely yours), you'll need to add the following line to your /boot/config.txt:
dtoverlay=w1-gpio

In /etc/modules, add the following modules:
w1-therm
w1-gpio pullup=1

Reboot. Now check that you can read the temperature from the sensor. Go to /sys/bus/w1/devices. In there there should be a folder whose name starts with "28-". It is the serial number of the sensor when its data is stored. In that folder there should be a file called w1_slave that should contain something like the following:

31 01 4b 46 7f ff 0c 10 4a : crc=4a YES
31 01 4b 46 7f ff 0c 10 4a t=19062

If that's the case, everything is good and that's where we'll read the temperature on the pi. The temperature is stored in thousands of a degree Celsius so we'll convert it in time.

Now, what we need is to collect the temperature from several pis (4 in my case). We have 2 alternatives: make the pis all write to a central place, or have the central place poll the pis. Writing to a central place has the advantage that data is stored only when it's available (e.g. if no temperature is read for a while you don't end up storing the last good temperature). But the downside is that you might have gaps in the data and also it could make the central place work harder because the pis won't be synchronised. So I decided to do a mix of the two: the pis collect their local data and make it available, and the central pi polls them when needed.

We therefore need to install two things: apache and php by running.
apt-get install apache2 php5

Then we need a script that will read the temperature from the sensor and make it available:
<?php

$file = file_get_contents("/sys/bus/w1/devices/YOURDS18B20SERIALHERE/w1_slave");
$lines = explode("\n", $file);
$l2 = $lines[1];
$a = explode(" ", $l2);
$temp = str_replace("t=", "", $a[9]);
$temp = ($temp/1000)+0;

file_put_contents("/var/www/html/temp.html", $temp);

?>
The script will make a static file available through apache for clients to read.

Finally, we need to run it regularly by adding the follwing to crontab:
* * * * * /usr/bin/php /root/temp.php  2>&1 > /dev/null

All the pis involved in the temperature monitoring scheme need that script running so that the controlling pi can collect the temperatures.

On the controlling pi, we need to install mysql to store the data:
apt-get install mysql php5-mysql

We'll need to create a database and table to store the data. Connect to mysql (command line or phpMyAdmin) and create the database and table:
create database Monitoring;
use Monitoring;
create table Bedroom(ComputerTime INTEGER UNSIGNED,Temperature DECIMAL(5,1), Humidity DECIMAL(5,1));
(note that the humidity field is only useful if you have humidity readings. I my case I have a mix so I use it)

I created a table like the above for each of the pis having a sensor. An alternative would have been to add a field setting where the temperature came from in a single table storing everything.

We then need a script that will read the remote temperatures and store them in the datbase. That's simply done with a script as follows:

<?php

include_once("config.inc");

function readBedroomTemperature() {
        return file_get_contents("http://IPOFTHEPI:PORTOFTHEPI/temp.html");
}

function saveBedroomTemperature($temp) {
        global $dbhost, $dbuser, $dbpass, $dbdb;

        $res1 = mysql_connect($dbhost, $dbuser, $dbpass);
        if (mysql_select_db($dbdb)) {
                $result = mysql_query("insert into Bedroom (ComputerTime, Temperature) VALUES (".time().", ".$temp.")");
                if (!$result) {
                        print(mysql_error());
                }
        } else {
                print("Couldn't select database\n");
                print(mysql_error());
        }
        mysql_close($res1);
}

$temp = readBedroomTemperature();
saveBedroomTemperature($temp);

?>

The config.inc file included contains static settings such as username and password for the database server.

Schedule the script as often as you want in crontab:
* * * * * /usr/bin/php /root/Boiler/updateBedroom.php 2>&1 > /dev/null

And repeat for each of the pis you have. It's cleaner to create a single script that will poll all known pis instead of running an independent script for each pi, which is a trivial change.

We now have a database that contains all the temperatures for all the pis in the house. We can do two things: draw fancy graphs, and make decisions on how to run the boiler.

For fancy graphs I used phpGraph and fed it the raw data. The script gets the data out of the database, and creates the graphs for each pi. This isn't needed to control the heating, but it's nice to see what's happening around the house:
I added a link to switch on/off the heating manually. I leave to your imagination what to do for that page.

Next step: control the boiler using the temperature readings


No comments:

Post a Comment