Thursday, January 7, 2016

DS18B20 temperature sensor with the Raspberry Pi

The Raspberry Pi is an ideal device as the central component in DIY projects like home automation or a weather station. One of the key sensors in these projects is a temperature sensor. In this blog post a tutorial will be provided on how to get started with some of these temperature sensors. This tutorial is a follow-up on my previous post about installing python 3.5.1 on the Raspberry Pi. However, in this tutorial I'm not (yet) using features of python that are not supported by the system installed version (3.4.2).

There are a lot of cheap temperature sensors available for these kind of projects on eBay. The first sensor that will be used in this tutorial is the  DS18B20. This component provides 9-bit to 12-bit Celsius temperature measurements, it also has an alarm function with nonvolatile user-programmable upper and lower trigger points. The DS18B20 communicates over a 1-Wire bus. If used in parasite power mode, this bus only needs 2 lines (data and ground) but power can also be provided by the third line. It measured temperature in the range of -55°C to +125°C and is accurate to ±0.5°C over the range of -10°C to +85°C. This component can be found in two versions a "normal" version (it looks like a transistor) and a waterproof version. The last one is nice for outdoor projects!

For this tutorial, the sensor is connected to the raspberry pi as follows:

  • PIN1: GND (pin 6)
  • PIN2: GPIO4 (pin 7) and with a 4.7k resistor to 3V3 (pin 1)
  • PIN3: 3V3 (pin 1)
As the latest raspbian is used, the drivers for the one-wire protocol are installed. They only need to be loaded on boot. Therefore, you need to add the following line to the file /boot/config.txt and reboot:

dtoverlay=w1-gpio

If you correctly connected the sensors, they should be detected by the system. Every one-wire sensor can be identified with its unique 64-bit identifier. In my case, I have two DS18B20 sensors connected in parallel (only one 4.7k resistor is needed). You can see which sensors are connected on the filesystem with the following command:

$ ls -als /sys/bus/w1/devices/
total 0
0 drwxr-xr-x 2 root root 0 Jan  7 21:57 .
0 drwxr-xr-x 4 root root 0 Jan  1 20:19 ..
0 lrwxrwxrwx 1 root root 0 Jan  2 12:57 28-0115153376ff -> ../../../devices/w1_bus_master1/28-0115153376ff
0 lrwxrwxrwx 1 root root 0 Jan  7 21:57 28-0215649194ff -> ../../../devices/w1_bus_master1/28-0215649194ff
0 lrwxrwxrwx 1 root root 0 Jan  7 21:57 w1_bus_master1 -> ../../../devices/w1_bus_master1

The sensor data can be gathered by reading the w1_slave file in each sensor folder. This file handle provides the most recent sensor data if the CRC check is valid. The value provided divided by 1000 is the temperature in °C. In this case, the sensor measures 20.75 °C.

$ cat /sys/bus/w1/devices/28-0115153376ff/w1_slave
4c 01 55 00 7f ff 0c 10 be : crc=be YES
4c 01 55 00 7f ff 0c 10 be t=20750

So a very basic python program that scans for available one-wire temperature sensors and dumps the current temperature is:

$ cat blog-temp.py 
import os

DEVICE_ROOT_DIR = '/sys/bus/w1/devices/'

def read_temp (device):
  full_filename = '{}{}/w1_slave'.format (DEVICE_ROOT_DIR, device)
  if not os.path.isfile (full_filename):
    raise IOError ('Temperature device {} not found on one-wire'.format (device))
  with open ('{}{}/w1_slave'.format (DEVICE_ROOT_DIR, device)) as f:
    lines = f.readlines ()
    status = lines[0][-4:-1]
    if status == 'YES':
      tempstr = lines[1][-6:-1]
      return float (tempstr) / 1000
    else:
      return None

def scan ():
  for filename in os.listdir (DEVICE_ROOT_DIR):
    if filename.startswith ('28-'):
      yield filename

if __name__ == '__main__':
    for device in scan ():
        print ("Temperature {}: {} °C".format (device, read_temp (device)))

If you run this program you can get the following output:

$ python3 blog-temp.py 
Temperature 28-0215649194ff: 18.187 °C
Temperature 28-0115153376ff: 20.812 °C

So, this was an introduction to the first temperature sensor. In a next blogpost, I will provide more information on the DHT11 sensor. This sensor also measures the humidity. However, it needs a bit more work to be used with a Raspberry Pi.

Friday, January 1, 2016

Build your own python version on Raspberry Pi

This post will provide a tutorial on how to install a specific python version on the raspberry pi. By default, raspbian does only provide a two python versions. At the time of writing, these python versions are respectively python 2.7.9 and python 3.4.2. Therefore, the available python versions lack support for the new async and await support introduced in python 3.5. This post can also be usefull if you need to build a specific older version of python for compatibility reasons.
You can already find some tutorials for building python 3.5 on the raspberry pi 2. However, this tutorial overwrites the system python version and so potentially it can break other programs.
In this tutorial, pyenv will be used to build and maintain different python versions next to each other.

Prepare the system

As a good practice, first update/upgrade the system packages to the latest versions.

$ sudo apt-get update
$ sudo apt-get upgrade -y
$ sudo apt-get dist-upgrade

Some specific software packages will be needed as a dependency to build python (or optional python modules).

$ sudo apt-get install build-essential libncursesw5-dev libgdbm-dev libc6-dev zlib1g-dev libsqlite3-dev tk-dev libssl-dev openssl libbz2-dev libreadline-dev

Installing pyenv

In this post, everything will be installed in the home folder of the current user. Feel free to adapt the install location to a different location on the system if it should be shared with different users. Installing pyenv and pyenv-virtualenv is as simple as cloning the git repos and set some paths in the environment. Note that pyenv provides full code completion on the shell!

git clone https://github.com/yyuu/pyenv.git ~/.pyenv

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.profile

Now, relaunch the shell (or logout and login) to initialize pyenv in your shell.

Installing python

Finally, a specific python version can be installed in the pyenv folder. In this case, python 3.5.1 is being installed. Note that this can take a while.

$ pyenv install 3.5.1
Downloading Python-3.5.1.tgz...
-> https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tgz
Installing Python-3.5.1...
Installed Python-3.5.1 to /home/pi/.pyenv/versions/3.5.1

A specific python version can now be activated with the following commands:

pi@raspberrypi:~ $ pyenv versions
* system (set by /home/pi/.pyenv/version)
  3.5.1
pi@raspberrypi:~ $ pyenv shell 3.5.1
pi@raspberrypi:~ $ python --version
Python 3.5.1