Monitor temperature and humidity with DHT11 sensor on raspberry pi

The DHT11 sensor includes a temperature and a humidity sensor. I connected it with my raspberry pi and transmit the data to an external cacti server, which polls the data regularly from the raspberry pi.

Step 1: Wire the sensor

While facing the open side of the sensor (NOT the one with the sticker on it), connect the pins as following

  • Leftmost pin = V+ — connect with 3V3 (Pin 1) from raspberry pi
  • Second pin = DATA — connect with GPIO4 (Pin 7) from raspberry pi AND via a 4.7k-10k resistor with 3V3
  • Third pin = Do NOT connect
  • Rightmost pin = GND — connect with GND (Pin 6) from raspberry pi
Raspberry PI Rev2 GPIO pinout
Raspberry PI Rev2 GPIO pinout

Step 2: Get the BCM2835 library and compile / install

The latest version can always be found here: http://www.airspayce.com/mikem/bcm2835/
As the time of writing, this was 1.36

cd
mkdir -p work/bcm2835
cd work/bcm2835
wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.36.tar.gz
tar xvfz bcm2835-1.36.tar.gz
cd ./bcm2835-1.36
./configure
make
sudo make install

Step 3: Get the Adafruit python code

sudo apt-get update
sudo apt-get -y install git
git clone https://github.com/adafruit/Adafruit-Raspberry-Pi-Python-Code
cd ./Adafruit-Raspberry-Pi-Python-Code
cd ./Adafruit_DHT_Driver
make

After successfully compiling the Adafruit Driver, you can check if your sensor is already working. Keep in mind that the DHT11 is SLOW and won’t react if asked more than once within 2 or 3 seconds. If you don’t get any result after the first query, wait a few seconds (at least 3) and try again. If the problem persists, your wiring might be wrong.

sudo ./Adafruit_DHT 11 4

Step 4: Modify Adafruit python code

The original Adafruit code is giving too much information for simple cacti input parameters. A modification of the source code is necessary. Along with changing the output, I also removed all references to DHT22 and AM2302 to make the file a bit smaller:

ada_sm.c

//  How to access GPIO registers from C-code on the Raspberry-Pi
//  Example program
//  15-January-2012
//  Dom and Gert
// Access from ARM Running Linux
#define BCM2708_PERI_BASE        0x20000000
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <bcm2835.h>
#include <unistd.h>
#define MAXTIMINGS 100
 
#define DHT11 11
 
int readDHT(int type, int pin);
 
int main(int argc, char **argv)
{
  if (!bcm2835_init())
        return 1;
 
  if (argc != 3) {
        printf("usage: %s [11] GPIOpin#\n", argv[0]);
        printf("example: %s 11 4 - Read from an DHT11 connected to GPIO #4\n", argv[0]);
        return 2;
  }
  int type = 0;
  if (strcmp(argv[1], "11") == 0) type = DHT11;
  if (type == 0) {
        printf("Select 11 as type!\n");
        return 3;
  }
  int dhtpin = atoi(argv[2]);
  if (dhtpin <= 0) {
        printf("Please select a valid GPIO pin #\n");
        return 3;
  }
  readDHT(type, dhtpin);
  return 0;
} // main
 
int bits[250], data[100];
int bitidx = 0;
 
int readDHT(int type, int pin) {
  int counter = 0;
  int laststate = HIGH;
  int j=0;
 
  // Set GPIO pin to output
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_OUTP);
 
  bcm2835_gpio_write(pin, HIGH);
  usleep(500000);  // 500 ms
  bcm2835_gpio_write(pin, LOW);
  usleep(20000);
 
  bcm2835_gpio_fsel(pin, BCM2835_GPIO_FSEL_INPT);
 
  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
 
  // wait for pin to drop?
  while (bcm2835_gpio_lev(pin) == 1) {
    usleep(1);
  }
 
  // read data!
  for (int i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while ( bcm2835_gpio_lev(pin) == laststate) {
        counter++;
        //nanosleep(1);         // overclocking might change this?
        if (counter == 1000)
          break;
    }
    laststate = bcm2835_gpio_lev(pin);
    if (counter == 1000) break;
    bits[bitidx++] = counter;
 
    if ((i>3) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > 200)
        data[j/8] |= 1;
      j++;
    }
  }
 
  if ((j >= 39) &&
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
     if (type == DHT11)
        printf("temp:%d hum:%d\n", data[2], data[0]);
    return 1;
  }
 
  return 0;
}

Compile the file with this command line (if you saved the above .c-file as „ada_sm.c“)

gcc ada_sm.c -l bcm2835 -std=gnu99 -o ada_sm

The output should be compatible with cacti:

$ sudo ./ada_sm 11 4
temp:23 hum:33

Step 5: Add a socat service

I’ve explained how to achieve this in another post, you only need a new shell script which will make sure that the readouts were given:

/usr/local/bin/dht11.sh

#!/bin/bash
result=""
while [ -z "${result}" ];
do
result=$(sudo /home/pi/work/dht11/ada_sm 11 4)
sleep 3
done
echo ${result}

Here the contents the configuration file for socat:

/etc/default/socat

OPTIONS="-T 30 -t 30 tcp-l:9889,reuseaddr,fork,crlf system:\"/usr/local/bin/dht11.sh\""

Step 6: Read data from the socat service on the cacti host

This is explained in another post as well, but the needed script in the site/scripts-directory is a bit different, here’s what I used. Keep in mind that you have to change „PI-IP“ to your local DNS or IP-Adress of the Raspberry Pi.

/usr/share/cacti/site/scripts/dht11.sh

#!/bin/bash
outstring=$(/bin/nc PI-IP 9889  | tr -d '\r')
echo "${outstring}"

Resources on the internet

These links helped me set this up:
http://www.messtechniklabor.de/artikel-h0000-temperatur_und_luftfeuchtigkeit_messen.html
https://learn.adafruit.com/dht-humidity-sensing-on-raspberry-pi-with-gdocs-logging/wiring
http://www.airspayce.com/mikem/bcm2835/

Schreibe einen Kommentar