Raspberry Pi Temperature & Humidity Network Monitor




Introduction: Raspberry Pi Temperature & Humidity Network Monitor

Please note that there's a Git repo for code at:


If you'd like the latest fixes or would like to contribute. Thanks Jonny Ervine!

I had some issues with Kingston SD Cards, but the SanDisk cards I'm using now have run for weeks without issues, so I'm changing the parts list to reflect that.

Also, after some 49 days, 16 hours, the display flatlines, as the reading routines start returning the same number over and over again. A reboot clears it, so just reboot once a month until I figure out what's up.

Over the past summer, my vacation home had a small water leak for three months, and I realized that had I been measuring the humidity in the effected area, I'd have
seen it go to 100% for a long time and I could have dispatched someone to fix the small problem before it became a big one.
And since I've been playing with Raspberry Pi computers for a while now, and saw an inexpensive temperature/humidity sensor on AdaFruit, I had all the pieces I needed
to implement an inexpensive network-connected monitor.
The Bill Of Materials (BOM):
1) Raspberry Pi Model B
2) Case
3) SD Card
4) Temperature/Humidity sensor
5 ) Power Supply (I use PoE splitters, but any 5V 1A Micro-USB supply will work)
I used the following exact parts, but obvious substitutions can be made to match local conditions and the state of your junk box. Shipping and the availability of bundles
may effect your final price.
$35.00 RPi http://www.newark.com/raspberry-pi/raspbrry-modb-...
$ 8.12 Case http://thepihut.com/products/classic-raspberry-pi... (5.99 Euros)
$ 6.99 SD Card (Sandisk, not Kingston)
$15.00 Sensor http://www.adafruit.com/products/393
$15.99 PoE Splitter http://www.newegg.com/Product/Product.aspx?Item=N...
And a few other miscellaneous things like hand tools, soldering iron, hot melt glue gun, small pieces of plastic wood, etc.

Step 1: Physical Assembly

Split the case, find the hardware bag inside, and set the rubber feet aside for later.

Attach the Raspberry Pi to the case bottom with the supplied hardware.

Remove the GPIO knockout with a razor blade or Xacto knife and snap the two case halves together.

To keep the power dissipation of the power supply and Raspberry Pi from effecting the sensor readings, I cut a piece of Azek plastic lumber about 1.1 x 2.4 x 0.75 inches as a standoff.

Heat up your hot-melt glue gun and stack the parts as in the picture. You'll have a few seconds to make the alignment perfect before the glue sets, so get the alignment close before you press the parts together.  Be careful not to use so much glue that it extrudes from the edges of the seams or extrudes into the case, where it might interfere with the SD card connector.

1) Glue the sensor to the standoff

2) Glue the standoff to the top half of the case. Be careful not to block the LED cutouts on the one side or the ribbon cable cutout for the camera on the other side.

3) Glue the case bottom to the top of the PoE adapter. Make sure the "LAN Out" connector is on the same side as the Raspberry Pi Ethernet adapter.

4) Stick the 4 rubber feet to the bottom of the power adapter.

5) Ensure the voltage-output selection switch is set to 5V. Put a dab of hot-melt glue in the switch to prevent it from being changed and destroying your Raspberry Pi.

Step 2: Electrical Assembly

The White wire from the sensor is a spare ground, and is not needed.  Cut it off inside the sensor case, being careful not to cut any of the other wires.

Braid the other three wires to keep them together, and cut them off about 3.5 inches long.

Prepare a 5-pin single inline female connector (cut from https://www.sparkfun.com/products/115 or equivalent), and solder the wires to it:

1) Red (+3.3V)
2) No Connection
3) No Connection
4) Yellow (Data)
5) Black (Ground)

Plug the connector into the GPIO on the Raspberry Pi so that pin 1 on the connector (red wire) is on pin 1 of the GPIO connector (label P1 on the board, upper right in the picture).  Note that the Red wire is on GPIO Pin 1 (+3.3V), the Yellow wire is on GPIO pin 7 (GPIO 4), and the Black wire is on GPIO Pin 9 (Ground).

Tuck the excess wire into the case.

Use a short CAT5 cable (something like http://www.monoprice.com/Product?c_id=102&cp_id=10232&cs_id=1023201&p_id=7505 ) to connect the LAN OUT on the PoE splitter and the Raspberry Pi Ethernet jack.  Twist it up to make it stay close to the case.

Take the PoE output cable and a Micro-USB connector or cable and solder them together.  If using an AdaFruit http://www.adafruit.com/products/1390 Micro-USB connector, wire it up as shown at http://learn.adafruit.com/assets/12402 , if using a cut-off cable, determine +5 and Gnd wires with a multimeter.  Note that the TP-Link wire with the white stripe is POSITIVE.

Step 3: Raspberry Pi Software Setup

Getting the basic Raspberry Pi software up and running has been documented elsewhere, but basically, go to:
download the latest NOOBS (v1.3.2 as of this writing)
Format the SD card using the SD card tool at https://www.sdcard.org/downloads/formatter_4/
Unzip the NOOBS file and put the contents at the root of the SD card.
Insert the SD card into the Raspberry Pi
Connect a keyboard, monitor, mouse, and LAN cable to the Raspberry Pi and connect the power supply (when you plug the PoE splitter into the LAN cable, the Raspberry Pi will power up).

Select the Raspian distribution and install it.
While that's installing, select English-US keyboard, which autoselects US Keymap

On first boot, the raspi-config utility will run.
Select Console Login as the default on boot
Change Locale to en_US UTF-8
Set timezone for your location
Set keyboard to Generic 105-key, English US
Enable the camera
change the hostname to something memorable (I used 'rpithon' for Raspberry Pi Temp/Humid On Net)
set 16M memory split as we'll be running headless
Enable SSH

Now you can either continue to use the console or ssh to it from another machine.  From my Mac I can just say:
ssh pi@rpithon
and log in using the password 'raspberry'.  If your router doesn't do the DNS to help you find 'rpithon' then make note of the IP address on the console and use that instead.

Update everything (this will take a while):

sudo apt-get update
sudo apt-get upgrade
sudo rpi-update

and reboot

Since this is going to be a LAN-only device, I get sick of playing "Mother May I?" with sudo, and I want to avoid any permissions problems with the additional software, so let's enable the root user and delete the pi user:

sudo passwd root
<rootpassword> repeated twice

log back in as root user (or ssh root@rpithon) using the password selected above

remove pi user:

deluser -remove-home pi

I prefer Emacs, and don't want all the X-Windows stuff, so:

apt-get install emacs23-nox

Tell it to check the disk (SD Card) every time it boots:

tune2fs -c 1 /dev/mmcblk0p6

emacs /etc/ssh/sshd_config

change X11Forwarding to no
UseDNS no
ClientAliveInterval 60

service ssh restart

Step 4: Setting Up LAMP Server (web Server)

So we want to be able to see the graphs we'll be generating (below), so we need to install a LAMP server.

LAMP: /Linux/Apache/MySQL/PHP&Perl

Linux is the operating system you are using (Raspian is a version of Debian, which is one of the common flavors of Linux)
Apache is the name of the web server software
MySQL is a SQL (Standard Query Language) database interface.  Databases sound really scary, but they are easy to use for simple things once you get used to them.
PHP and Perl are programming languages that are commonly used with websites, though we'll be using the Raspberry Pi standard Python for graphing the data and 'creating' the website.

apt-get install apache2  php5 mysql-client mysql-server vsftpd

This takes a while to install.  Midway through it'll ask you for a MySQL password, pick one memorable, I'll use 'password' for this tutorial.

Now you should be able to browse to http://rpithon (or http://<IP ADDRESS> if the DNS doesn't work) and see a demo web page.  Try to edit /var/www/index.html and see if your changes show up when you refresh the webpage.

Step 5: Ez_setup, MySQL, Matplotlib

ez_setup is a Python program that loads some nice addons (think of it as apt-get on steroids)

wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
python ez_setup.py

These next steps install some integration between Python and MySQL:

apt-get install python-mysqldb
apt-get install libmysqlclient-dev
easy_install MySQL-python

We'll be using the wonderful, powerful, and free(!) matplotlib for graphing our data, though we won't be using much of its power.

apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools python-scipy python-matplotlib

Step 6: WiringPi - GPIO Interface

Gordon Henderson has created a wonderful programming interface for the GPIO pins, including some drivers for the esoteric interface that our Temperature/Humidity sensor uses.  See http://wiringpi.com/ for more details.

git clone git://git.drogon.net/wiringPi
cd wiringPi
cd examples
emacs rht03.c (change the line #define RHT03_PIN 0 to #define RHT03_PIN 7 for the GPIO pin we're using)
make rht03
(you should get continuous temperature and humidity readings)

now we know our hardware is working, let's write our own program...

Step 7: Set Up a Database and a Table

So we have database software, but there's no database, or tables, so let's create them:

Open the MySQL command interface:

mysql -ppassword <-- the mysql password you picked previously


Create a new database, called Monitoring

mysql> create database Monitoring;
Query OK, 1 row affected (0.00 sec)

Select that as our current database

mysql> use Monitoring;
Database changed

Create a single table in the database called TempHumid, which will contain the Unix Epoch (seconds since 1970) and Temperature and Humidity readings

mysql>create table TempHumid (ComputerTime INTEGER UNSIGNED,Temperature DECIMAL(5,1), Humidity DECIMAL(5,1));
Query OK, 0 rows affected (1.70 sec)

Done with MySQL, exit back to the command prompt.

mysql> exit

Step 8: Add Readings to the Database

Because the timing is tight on the sensor protocol, we're going to use C code to communicate with the sensor and add readings to the database.

So go to the root user's default directory:

cd ~

copy the Makefile (instructions on how to build the code we're going to create)

cp wiringPi/examples/Makefile .

emacs makeFile
change the two lines below to match this:

INCLUDE = -I/usr/local/include,/usr/include/mysql

LDFLAGS = -L/usr/local/lib,/usr/lib/arm-linux-gnueabihf -lmysqlclient -lpthread -lz -lm -lrt -ldl

Now copy th.c (included here) into your default directory. Change the password on line 68 from "password" to whatever you chose as the MySQL password.

When you compile it:

make th

you'll get a couple of warnings about declarations of exit, but it'll work fine.

Now you can run the program by typing:


It waits for a 60-second interval (minute) to end, then reads the sensor, inserts the time and sensor readings into the database, and loops forever.

Once we have that working properly, we want it to start whenever the Raspberry Pi starts up:

emacs /etc/rc.local

/root/th >> /root/th.log &

before the line that reads "exit 0"

reboot and see if th.log grows by one line per minute:

tail -f th.log

You can confirm that the data is getting into the database with:

mysql -ppassword
use Monitoring;
select * from TempHumid;

You should get a list of all values in the database.


Step 9: Graph Data From the Database

We're going to use Python for pulling readings out of the database and graph them with matplotlib.  Log in as root.

Set up the directory structure we'll be using:
mkdir Graph
cd Graph
mkdir graphics

copy GraphTH.py into the Graph directory
Change the password on line 40:
DBconn = mdb.connect('localhost', 'root', 'password', 'Monitoring')
to match the MySQL password you set previously.
You can also set <location_name> on line 81 to match your desired location name

Try running it:

python GraphTH.py

It will get the last 24 hours of readings from the database, reorganize the data, throw out obvious bad data, create a graph of the results, and copy TH.png to /var/www so you should be able to see a new graph time you run GraphTH.py  at http://rpithon/TH.png

Now we want this to run every minute, so:
export EDITOR=emacs
crontab -e
Add the line:
* * * * * /usr/bin/python /root/Graph/GraphTH.py >> /root/Graph/GraphTH.log
at the bottom of the file.

Now GraphTH.py should run every minute, and if you update http://rpithon/TH.png (or http://<IP ADDRESS>/TH.png you should see it change about once a minute.

In the example above I covered the sensor with a damp Kleenex while it dried as a test.

Step 10: Monitor More Than One Location

So I built five of these boxes for various locations, and on the LAMP server of one of them, added the following TH.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

    <meta http-equiv="refresh" content="60" />
    <meta http-equiv="content-type" content="text/html;charset=utf-8" />
    <title>Temperature and Humidity readings</title>

    <div id="outline">
      <div id="caption">
     Temperature and Humidity
     <br />
   <div id="text">
  Sensor locations:
  White  - A Room
  Green  - Another Room
  Blue   - A Place To Monitor
  Purple - Another Place
  Orange - Somewhere Else
  Graphs are updated every minute.
      <a    href="http://rpithon-wht/TH.png">
<img src="http://rpithon-wht/TH.png" align="center" width="320" height="240">
      <a    href="http://rpithon-grn/TH.png">
<img src="http://rpithon-grn/TH.png" align="center" width="320" height="240">
      <a    href="http://rpithon-blu/TH.png">
<img src="http://rpithon-blu/TH.png" align="center" width="320" height="240">
      <a    href="http://rpithon-pur/TH.png">
<img src="http://rpithon-pur/TH.png" align="center" width="320" height="240">
      <a    href="http://rpithon-org/TH.png">
<img src="http://rpithon-org/TH.png" align="center" width="320" height="240">

so now I can point my browser at: http://rpithon-wht/TH and see all of the graphs updated every minute.

Step 11: Extras - Camera

You remember how we enabled the camera module when we installed the Raspian operating system?  Now we can add a Raspberry Pi Camera module:

$25 http://www.newark.com/raspberry-pi/rpi-camera-board/add-on-brd-camera-module-raspberry/dp/69W0689

Just feed the camera cable through the slot in the top case and plug it into the connector on the Raspberry Pi as per the instructions at http://www.raspberrypi.org/camera using the connector next to the Ethernet port, with the tinned leads pointing away from the Ethernet connector.

I used another piece of Azek to position the camera with some hot melt glue, but there are obviously  a lot of options.

Now you can use the camera module to let you see into the area you are monitoring for temperature and humidity.  From another computer you can do something like:

ssh root@rpithon 'raspistill -o image.jpg'
scp root@rpithon:image.jpg .

Or have a cron job save a new file to the webserver on a regular basis!

In addition to the camera, there are lots of other peripherals and functions you can add to the Raspberry Pi, let your imagination guide you!

Raspberry Pi Contest

Finalist in the
Raspberry Pi Contest

5 People Made This Project!


  • Remote Control Contest

    Remote Control Contest
  • Stone Concrete Cement Contest

    Stone Concrete Cement Contest
  • Make It Modular: Student Design Challenge

    Make It Modular: Student Design Challenge


Ok gang, a colleague of mine helped out with a python script of his own that works really well with this project. You can set your temperature thresholds, and if three consecutive measurements exceed those thresholds, then an email is sent out using Python's mail feature. Example of the email received is below.

Temperature and/or Humidity Anomaly Detected!

Temperature exceeded threshold for 3 consecutive
measurements at 2015-02-24 16:25:00

Humidity exceeded threshold for 3 consecutive
measurements at 2015-02-24 16:25:00


I don't know how to attach the python script to this post, but I should probably make it available to wpnsmith so he can include it as an option.


Reply 4 years ago

Hello could you please send the email alerts script to me as well?


Reply 7 years ago on Introduction

Great, PM it to me and I'll figure out how to include it.



Reply 6 years ago

can u send me the script?


Reply 6 years ago

I can. Send me a private message and I will email you the python script for email alerts.


Reply 5 years ago

Hi Eduardo.

Will it be possible to send me the python script? I'm conducting a student project on the same topic and will be glad to have it as a reference.

You can mail it to me at qwamedusei@gmail.com


8 years ago on Introduction

Excellent guide! Thanks for doing this.

Quick question for you:

I was going through the code and I have been trying to figure out how instead of having the y axis go in increments of 20, could I have the scale be in increments of 10? (Still going to 100)
Thanks again!


Reply 8 years ago on Introduction

Good question! Sorry for the delay, the answer is well hidden. 8*)

in GraphTh.py after the line:





Tip 3 years ago on Step 3

Got stuck here, hoping this helps entry-level developers.

Enable root login over SSH:
  1. As root, edit the sshd_config file in /etc/ssh/sshd_config:
    nano /etc/ssh/sshd_config
  2. Add a line in the Authentication section of the file that says PermitRootLogin yes. This line may already exist and be commented out with a "#". In this case, remove the "#".
  3. # Authentication:
    #LoginGraceTime 2m
    PermitRootLogin yes
    #StrictModes yes
    #MaxAuthTries 6
    #MaxSessions 10
  4. Save the updated file/etc/ssh/sshd_config.
  5. Restart the SSH server:
    service sshd restart

4 years ago


i did everything as you. I got stucked on compiling the th file. What should i do? It is giving me this:
root@rpi:~# make th

gcc -O3 -Wall -I/usr/local/include,/usr/include/mysql -Winline -pipe -L/usr/local/lib,/usr/lib/arm-linux-gnueabihf -lmysqlclient -lpthread -lz -lm -lrt -ldl th.c -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt -o th

th.c:13:20: warning: extra tokens at end of #include directive

#include <stdio.h> include <wiringPi.h> include <maxdetect.h> include


th.c:14:2: error: invalid preprocessing directive #<

#<time.h> include <mysql/mysql.h> define RHT03_PIN 7 define CYCLETIME 60


th.c:16:24: error: unknown type name ‘MYSQL’

void finish_with_error(MYSQL *con) {


th.c: In function ‘main’:

th.c:28:3: error: unknown type name ‘time_t’

time_t oldtime,newtime; // when did we last take a reading?


th.c:32:3: error: unknown type name ‘time_t’

time_t rawtime;


th.c:36:18: warning: implicit declaration of function ‘time’ [-Wimplicit-function-declaration]

oldtime = (int)time(NULL);


th.c:37:3: warning: implicit declaration of function ‘wiringPiSetup’ [-Wimplicit-function-declaration]

wiringPiSetup () ;


th.c:38:3: warning: implicit declaration of function ‘piHiPri’ [-Wimplicit-function-declaration]

piHiPri (55) ;


th.c:39:10: warning: missing terminating " character

printf("rh.c rev 1.79 12/04/2013 WPNS %sCycle time: %i seconds, %i


th.c:39:10: error: missing terminating " character

printf("rh.c rev 1.79 12/04/2013 WPNS %sCycle time: %i seconds, %i


th.c:40:8: error: stray ‘\’ in program



th.c:40:1: error: ‘retries’ undeclared (first use in this function)



th.c:40:1: note: each undeclared identifier is reported only once for each function it appears in

th.c:40:9: error: expected ‘)’ before ‘n’



th.c:40:10: warning: missing terminating " character



th.c:40:10: error: missing terminating " character



th.c:80:25: warning: missing terminating " character

sprintf(SQLstring,"INSERT INTO TeplotaVlhkost


th.c:80:25: error: missing terminating " character

sprintf(SQLstring,"INSERT INTO TeplotaVlhkost


th.c:81:42: warning: missing terminating " character

VALUES(unix_timestamp(now()),%5.1f,%5.1f)",(temp / 10.0),(rh / 10.0));


th.c:81:42: error: missing terminating " character

VALUES(unix_timestamp(now()),%5.1f,%5.1f)",(temp / 10.0),(rh / 10.0));


th.c:90:1: error: expected declaration or statement at end of input



th.c:34:7: warning: unused variable ‘status’ [-Wunused-variable]

int status; // how did the read go?


th.c:33:15: warning: unused variable ‘timeinfo’ [-Wunused-variable]

struct tm * timeinfo;


th.c:32:10: warning: unused variable ‘rawtime’ [-Wunused-variable]

time_t rawtime;


th.c:31:8: warning: unused variable ‘TimeString’ [-Wunused-variable]

char TimeString[64]; // formatted time


th.c:30:8: warning: unused variable ‘SQLstring’ [-Wunused-variable]

char SQLstring[64]; // string to send to SQL engine


th.c:28:18: warning: unused variable ‘newtime’ [-Wunused-variable]

time_t oldtime,newtime; // when did we last take a reading?


th.c:28:10: warning: variable ‘oldtime’ set but not used [-Wunused-but-set-variable]

time_t oldtime,newtime; // when did we last take a reading?


th.c:26:7: warning: variable ‘temp’ set but not used [-Wunused-but-set-variable]

int temp, rh ; // temperature and relative humidity readings


<builtin>: recipe for target 'th' failed

make: *** [th] Error 1


Reply 4 years ago

I'm at the "make th" step too, but get this attached error. Any thoughts? Trying to make the th.py above looked way worse. The python ez_setup is non-existant, so maybe that's what I'm missing... Is there an alternative to that?

Thanks for coming back to reply to these posts once in a while. Though dated, between comments and Google I've gotten this far, and even have the RTSP camera server running on my Pi, so it's not totally useless :)

Edit: I included the stdlib.h library, but still get the "recipe for target th failed" error.


Question 4 years ago on Step 4

please help me, i have rpoblem to access http://rpithon. --> 10001_Domain has been blocked. (ZoneId_1081689)


Question 4 years ago

Are there any updates to GraphTH.py ? There are a few 'depreciated' errors and it's preventing me from running this. Can anyone update this?


4 years ago

Any idea if the data can be read from SNMP polls? We want to build this to use it with Icinga2 and have Icinga2 poll the device via SNMP for the data then alert the appropriate groups.

Thanks gang for your Public knowledge. I wish to buy some of your device that you've used it for learning & my study researching.

Would you email me all list product name of you used it, please

Where do i get these device? What kinds language program do you used to designing your project? would you email me your script, please?

Here is my email,horas.sahala.marbun@gmail.com

thanks gang,


4 years ago

This is pretty dated and some links are broken. Any way to get this updated from original and all the comments and moved files for Raspberry Pi 3?


Reply 4 years ago

Yeah, it's been a few years, and I've changed the sensor and rebuilt it on the latest Jessie release, but finding the time to redo the Instructable is now the hard part. It's amazing how much time something like that takes...

It's on my list of projects, but I've got tradeoffs between building Instructables and hacking my own projects....

When I get a Round Tuit 8*)


6 years ago

I can't get it to start TH.c when it boots. It's pretty confusing since my rc.local file is essentially empty except for the /root/th >>
/root/th.log & entry. I can tell it to print to the screen before and after that line and it does that just fine, and I can start the program manually after it boots up.


Reply 6 years ago

I'll say I had an issue with mine as well. I'm assuming being this recent you're running the newest image of Raspbian (Jessie), which is apparently known to have issues with certain things running out of the rc.local file (other comments below recognizing this, but not with any real solution). However, the issue I saw was not the rc.local file not running, it was that the file would run at boot but wouldn't actually read from the sensor. When I ran the tail cmd I would get that it was just printed up to the "Sync to cycletime..." message into the logfile but none of the temp entries -- and no entries were being added to the database. To get around this issue, I created a systemd service file and have enabled it to run at boot that way. This required modifying the th.c file to create a daemon as well. If you need any help figuring it out, let me know.