Tag Archives: temperature

Monitor Temperature and Humidity using Raspberry Pi

Today I would like to share you the way to monitor via web page temperature and humidity using raspberry Pi and Sensor for humidity and temperature. You could find a lot of similar articles in the Internet. Mine solution is just combination of several and small adjustment.

Level of moisture in our house is too high and this requires intervention from our side to reduce it. Recommended value of moisture should be between 35% and 55%. High level of moisture increase probability to get ingress on our things, clothes, walls..

Moisture level depends on air flows and temperature in your house. If in the winter temperature is below 20 Celsius degree the level of humidity will be higher than recommended value. Minimum recommended level of temperature should be 21 Celsius degrees.  In other words you need to have smart heating system and good ventilation to reduce fast humidity when you are cooking or after you used bathroom. So let’s see how to get data which we need for decisions.

We need equipment:

  • DHT22 AM2302 Digital Temperature and Humidity Sensor module Replace SHT11 SHT15, Price – 5.97 USD
  • Raspberry Pi-2 + Acrylic Enclosure Case + Heat sink, Price – 42.27 USD 

Let’s connect sensor to the raspberry. I did everything like in this link http://www.home-automation-community.com/temperature-and-humidity-from-am2302-dht22-sensor-displayed-as-chart/ except the thing that I didn’t used resistor and development plate. My sensor has resistor built in. Here is my equipment and connections:

Before to collect data let’s update our raspberry:

sudo aptget update

Note: Many steps in this tutorial require internet acces on raspberry PI (If you don't know how to do it see my previous article how to connect raspbery to the internet via Wi-Fi)

Raspberry collect data from sensor on the GPIO pin 4. To read data we will use python library called Adafruit_Python_DHT.

To install library, get the dependencies with:

sudo aptget install y buildessential pythondev git

and then download and install the library with:

mkdir -p /home/pi/sources 
cd /home/pi/sources 

git clone https://github.com/adafruit/Adafruit_Python_DHT.git 

cd Adafruit_Python_DHT 

sudo python setup.py install 

 Here we can do fast check to see that Pi is ready to collect data from sensor:

sudo /home/pi/sources/Adafruit_Python_DHT/examples/AdafruitDHT.py 2302 4

The first argument is the sensor type, it can be 11 or 22 or 2302. The second argument is the RPi GPIO pin which is connected to the sensor data pin.

Output will be like:

sudo /home/pi/sources/Adafruit_Python_DHT/examples/AdafruitDHT.py 2302 4

Temp = 24.2*C Humidity=26.3%

Let’s create sql database to collect our data

Install sqlite

sudo apt-get install sqlite3

  Create DB schema

BEGIN;

CREATE TABLE temp_hum (timestamp DATETIME, temp NUMERIC, hum NUMERIC);

COMMIT;

Great, now we have DB where we could write data. We created table called temp_hum. This table has 3 columns: timestamp, temp and hum. First column will contain actual date and time. So let’s assure that time and data is right. Use date command to check it.

If something is wrong let’s install ntpdate packet and adjust time:

sudo apt-get install ntpdate

sudo service ntpd stop

sudo ntpdate time.nist.gov

sudo service ntpd start

Last step is to adjust timezone. For me timezone is GMT+3. Find your on the internet if you don’t know which one is yours.

sudo cp /usr/share/zoneinfo/Etc/GMT+3 /etc/timezone

Let’s install and configure web server

sudo apt-get install apache2

We will use cgi-bin scripts to display collected data on web page. So let's say apache web server to use them. This step could be optional for you:

a2enmod cgi

a2enmod cgid

service apache2 restart

Move created DB to the /var/www/ folder and change owner of DB:

sudo cp templog.db /var/www/
sudo chown www-data:www-data /var/www/templog.db 

Now we have to do little bit programming or just copy ready solution from the internet (as I did, thanks this author for help). I adjusted liitle bit found code in the internet in order to get expected results.

nano /root/monitor.py

and insert following text inside:

#!/usr/bin/env python

import sqlite3
import Adafruit_DHT
import os
import time
import glob

# global variables
dbname='/var/www/templog.db'

# store the temperature and hummidity in the database
def log_temperature(temp,humm):

    conn=sqlite3.connect(dbname)
    curs=conn.cursor()

    curs.execute("INSERT INTO temp_hum values(datetime('now'), (?), (?))", (temp,humm))
    #curs.execute("INSERT INTO temp_hum values(datetime('now'), (?))", (humm,))
    # commit the changes
    conn.commit()

    conn.close()


# display the contents of the database
def display_data():

    conn=sqlite3.connect(dbname)
    curs=conn.cursor()

    for row in curs.execute("SELECT * FROM temp_hum"):
        print str(row[0])+”     “+str(row[1])+”        “+str(row[2])

    conn.close()

# get temerature and humidity
# returns None on error, or the temperature,humidity as a float
def get_temp_hum():
        try:
                humm, temp = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 4)
                humm = round (humm, 2)
                temp = round (temp, 2)
                return humm, temp
        except:
                return None, None

# main function
# This is where the program starts
def main():
        # get the temperature from the device file
        humm, temp = get_temp_hum()
        # Store data to DB in case we have values
        if (humm != None and temp !='None'):
                log_temperature(humm, temp)
#       display_data()

if __name__=="__main__":
    main()

Let me add several comments to the code. First of all we defined database location dbname='/var/www/templog.db'. After that we defined function log_temperature to insert data in our DB. We have function called get_temp_hum to read data from the sensor using python library installed at the beginning of this article.The most important part is main function where we are calling get_temp_hum, check that we have valid data and insert them to DB using log_temperature. One more function display_data() is commented and we need it only for debug purposes. Uncomment this line and execute the script to assure that you have inserted data in the DB.

Don't forget to make file monitor.py executable:

chmod 755 /root/monitor.py

Let's collect data every 15 minutes. For this print:

crontab -e

Insert this line:

*/15 * * * * /root/monitor.py

Note: If execution of script fail for some reason try to excute script manually with sudo /root/monitor.py. Also you could monitor script execution in crontab using postfix mail service. To install it use sudo apt-get install postfix.

Last step is create script which will display data on the web page.

nano /usr/lib/cgi-bin/webgui.py

Insert there following text:

#!/usr/bin/env python
import sqlite3
import os
import sys
import cgi
import cgitb

# global variables
dbname='/var/www/templog.db'

# print the HTTP header
def printHTTPheader():
    print "Content-type: text/html\n\n"

# print the HTML head section
# arguments are the page title and the table for the chart
def printHTMLHead(title, table):
    print "<head>"
    print "    <title>"
    print title
    print "    </title>"

    print_graph_script(table)

    print "</head>"


# get data from the database
# if an interval is passed,
# return a list of records from the database
def get_data(interval):

    conn=sqlite3.connect(dbname)
    curs=conn.cursor()

    if interval == None:
        curs.execute("SELECT * FROM temp_hum")
    else:
        curs.execute("SELECT * FROM temp_hum WHERE timestamp>datetime('now','-%s hours') AND timestamp<=datetime('now')" % interval)

    rows=curs.fetchall()

    conn.close()
    return rows


# convert rows from database into a javascript table
def create_table(rows):
    chart_table=""

    for row in rows[:-1]:
        rowstr="[‘{0}’, {1}, {2}],\n”.format(str(row[0]),str(row[1]),str(row[2]))
        chart_table+=rowstr

    row=rows[-1]
    rowstr="[‘{0}’, {1}, {2}]\n”.format(str(row[0]),str(row[1]),str(row[2]))
    chart_table+=rowstr

    return chart_table


# print the javascript to generate the chart
# pass the table generated from the database info
def print_graph_script(table):

    # google chart snippet
    chart_code="""
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:[“corechart”]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          [‘Time’, ‘Humidity’, ‘Temperature’],
%s
        ]);
        var options = {
          title: 'Temperature and Humidity'
        };
        var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>"""

    print chart_code % (table)

 


# print the div that contains the graph
def show_graph():
    print "<h2>Temperature Chart</h2>"
    print '<div id="chart_div" style="width: 900px; height: 500px;"></div>'

# connect to the db and show some stats
# argument option is the number of hours
def show_stats(option):

    conn=sqlite3.connect(dbname)
    curs=conn.cursor()

    if option is None:
        option = str(24)

    curs.execute("SELECT timestamp,max(temp) FROM temp_hum WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option)
    tempmax=curs.fetchone()
    tempmax="{0}&nbsp&nbsp&nbsp{1} %".format(str(tempmax[0]),str(tempmax[1]))

    curs.execute("SELECT timestamp,min(temp) FROM temp_hum WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option)
    tempmin=curs.fetchone()
    tempmin="{0}&nbsp&nbsp&nbsp{1} %".format(str(tempmin[0]),str(tempmin[1]))

    curs.execute("SELECT avg(temp) FROM temp_hum WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option)
    tempavg=curs.fetchone()

    curs.execute("SELECT timestamp,max(humm) FROM temp_hum WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option)
    hummmax=curs.fetchone()
    hummmax="{0}&nbsp&nbsp&nbsp{1} C".format(str(hummmax[0]),str(hummmax[1]))

    curs.execute("SELECT timestamp,min(humm) FROM temp_hum WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option)
    hummmin=curs.fetchone()
    hummmin="{0}&nbsp&nbsp&nbsp{1} C".format(str(hummmin[0]),str(hummmin[1]))

    curs.execute("SELECT avg(humm) FROM temp_hum WHERE timestamp>datetime('now','-%s hour') AND timestamp<=datetime('now')" % option)
    hummavg=curs.fetchone()


    print "<hr>"


    print "<h2>Minumum Value&nbsp</h2>"
    print tempmin
    print hummmin
    print "<h2>Maximum Value</h2>"
    print tempmax
    print hummmax
    print "<h2>Average Value</h2>"
    print "%.1f" % tempavg+"%"
    print "%.1f" % hummavg+"C"
    print "<hr>"

    print "<h2>In the last hour:</h2>"
    print "<table>"
    print "<tr><td><strong>Date/Time</strong></td><td><strong>Temperature</strong><td><strong>Humidity</strong></td></td></tr>"

    rows=curs.execute("SELECT * FROM temp_hum WHERE timestamp>datetime('now','-1 hour') AND timestamp<=datetime('now')")
    for row in rows:
        tempstr="<tr><td>{0}&emsp;&emsp;</td><td>{1} %</td><td>{2} C</td></tr>".format(str(row[0]),str(row[1]),str(row[2]))
        print tempstr
    print "</table>"

    print "<hr>"

    conn.close()

def print_time_selector(option):

    print """<form action="/cgi-bin/webgui.py" method="POST">
        Show the temperature logs for
        <select name="timeinterval">"""


    if option is not None:

        if option == "6":
            print "<option value=\"6\" selected=\"selected\">the last 6 hours</option>"
        else:
            print "<option value=\"6\">the last 6 hours</option>"

        if option == "12":
            print "<option value=\"12\" selected=\"selected\">the last 12 hours</option>"
        else:
            print "<option value=\"12\">the last 12 hours</option>"

        if option == "24":
            print "<option value=\"24\" selected=\"selected\">the last 24 hours</option>"
        else:
            print "<option value=\"24\">the last 24 hours</option>"

        if option == "168":
            print "<option value=\"168\" selected=\"selected\">the last 168 hours</option>"
        else:
            print "<option value=\"168\">the last 168 hours</option>"

    else:
        print """<option value="6">the last 6 hours</option>
            <option value="12">the last 12 hours</option>
            <option value="24">the last 24 hours</option>
            <option value="168">the last 168 hours</option>"""

    print """        </select>
        <input type="submit" value="Display">
    </form>"""


# check that the option is valid
# and not an SQL injection
def validate_input(option_str):
    # check that the option string represents a number
    if option_str.isalnum():
        # check that the option is within a specific range
        if int(option_str) > 0 and int(option_str) <= 24:
            return option_str
        else:
            return None
    else:
        return None


#return the option passed to the script
def get_option():
    form=cgi.FieldStorage()
    if "timeinterval" in form:
        option = form[“timeinterval”].value
        return validate_input (option)
    else:
        return None

# main function
# This is where the program starts
def main():

    cgitb.enable()

    # get options that may have been passed to this script
    option=get_option()

    if option is None:
        option = str(24)

    # get data from the database
    records=get_data(option)

    # print the HTTP header
    printHTTPheader()

    if len(records) != 0:
        # convert the data into a table
        table=create_table(records)
    else:
        print "No data found"
        return

    # start printing the page
    print "<html>"
    # print the head section including the table
    # used by the javascript for the chart
    printHTMLHead("Raspberry Pi Temperature and Humidity Logger", table)

    # print the page body
    print "<body>"
    print "<h1>Raspberry Pi Temperature and Humidity Logger</h1>"
    print "<hr>"
    print_time_selector(option)
    show_graph()
    show_stats(option)
    print "</body>"
    print "</html>"

    sys.stdout.flush()

if __name__=="__main__":
    main()

Let me again comment the script. First of all we need to know how much hours to display in graph using get_option function. By default 24 hours will be displayed. Function get_data will collect dates from DB. If you have at least one string in the DB data will be converted create_table function to display everything on the web. Actual string is not converting data for 1 week. This is what I have to fix after.

Don't forget to make file webgui.py executable:

chmod 755 /usr/lib/cgi-bin/webgui.py

To see data in the web page open web browser on the PC in the same network with raspberry and insert in the address field:

192.168.1.10/cgi-bin/webgui.py

192.168.1.10 is the ip address of Pi

Final result look like this:

After 10 AM I moved sensor closer to the heating system. This is why we have so big changes in the graph.

Links

  1. http://www.home-automation-community.com/temperature-and-humidity-from-am2302-dht22-sensor-displayed-as-chart/
  2. https://github.com/adafruit/Adafruit_Python_DHT
  3. http://raspberrywebserver.com/cgiscripting/rpi-temperature-logger/building-a-web-user-interface-for-the-temperature-monitor.html