All Collections
IoT Projects Tutorials
Hands on the AirPi Kit v1.4, a weather station using Raspberry Pi
Hands on the AirPi Kit v1.4, a weather station using Raspberry Pi

AirPi is a shield to turn your Raspberry Pi into a weather station

David Sepúlveda avatar
Written by David Sepúlveda
Updated over a week ago

AirPi is an plug-and-sense, low cost weather station. It works as a shield for the Raspberry Pi, gathering data about temperature, humidity, air pressure, carbon monoxide, nitrogen dioxide, light levels, noise levels and even more. In this article we'll connect the AirPi Kit to the Ubidots cloud, creating a connected WiFi weather station.

1. Materials

  • Raspberry Pi Model B

  • USB WiFi Dongle

  • Airpikit v1.4 

The kit includes the following:

  • MCP3008 (adc converter)

  • LDR (Light dependent resistor GL5528)

  • DHT AM23602 (Humidity and temperature)

  • MICS-4514 (NO2  and CO concentrations)

  • MIC electret (noise mesuarement)

  • BMP085 (pression, temperature)

2. Welding

If you have your Airpi already assembled you can skip this step. If you don't, we recommend this guide.

3. Coding your Raspberry Pi

Before we can start coding we'll need to fullfill some requirements:

When ready, login through a terminal into your Raspberry Pi and set up the SPI module to communicate with the ADC:

sudo nano /etc/modprobe.d/raspi-blacklist.conf

Add a "#" character before the line spi-bcm2708, then press CTRL-X, type Y and Enter. This enables SPI from the boot.

Install the python library called Ubidots, to do so you need to install first a package manager called pip:

sudo apt-get install python-setuptools
sudo easy_install pip
sudo pip install ubidots 

Install the library called "py-spidev" in order to read data from SPI devices attached to the Raspberry Pi. To do this you'll have to install first "python-dev":

sudo apt-get install python-dev
mkdir py-spidev
cd py-spidev
wget https://raw.github.com/doceme/py-spidev/master/setup.py
wget https://raw.github.com/doceme/py-spidev/master/spidev_module.c
sudo python setup.py install

Awesome, SPI is ready, now we need to setup the Adafruit DHT library:

git clone https://github.com/adafruit/Adafruit_Python_DHT.git
sudo python Adafruit_Python_DHT/setup.py install

Now we need to restart the device:

sudo reboot

You can test if the library is working properly by typing:

cd Adafruit_Python_DHT/examples
sudo python AdafruitDHT.py 2302 4

We are ready to go. Now you can paste the following code into a new file called airpi.py (dont forget to put your own API Key):

sudo nano airpi.py

#!/usr/bin/env pythonimport time 						# Library for delaysimport RPi.GPIO as GPIO 			# Library for using the GPIO portsfrom  math import log1p,exp,log10 	# Library for math functions. No need for it if you'll get the raw data from the sensorsfrom ubidots import ApiClient  		# Ubidots Libraryimport Adafruit_DHT 				# Library from Adafruit to simplify the use of DHT sensor.# Set up the SPI interface pins. Through SPI we can connect to the ADC MCP3008SPICLK = 18SPIMISO = 24SPIMOSI = 23SPICS = 25GPIO.setmode(GPIO.BCM) 				# Set up BCM as numbering system for inputsGPIO.setup(SPIMOSI, GPIO.OUT)		# Configure the SPI I/OGPIO.setup(SPIMISO, GPIO.IN)GPIO.setup(SPICLK, GPIO.OUT)GPIO.setup(SPICS, GPIO.OUT)# Setup VariablesdS = None 							# Ubidots Data source. We'll call Airpisensor = Adafruit_DHT.AM2302			# Especify the DHT sensor we will use 									# You can change this line for other DHT sensors like this: Adafruit_DHT.DHT11 or Adafruit_DHT.DHT22light = 0 							# Save  value of the LDRnoise = 0 							# Save value of the Mic inno2 = 0 							# Save value for Nitrogen dioxide levelco = 0 								# Save value for Carbon monoxide levelhum = 0 								# Save value for Humiditytemperature = 0 						# Save value for Temperaturevin = 3.3  							# Voltage reference for the ADC    # Function to verify if the variable exists or not in your Ubidots accountdef getVarbyNames(varName,dS):	for var in dS.get_variables():		if var.name == varName:			return var	return None# Function from Adafruit to read analog valuesdef readadc(adcnum, clockpin, mosipin, misopin, cspin):        if ((adcnum > 7) or (adcnum < 0)):                return -1        GPIO.output(cspin, True)        GPIO.output(clockpin, False)  		# start clock low        GPIO.output(cspin, False)     		# bring CS low        commandout = adcnum        commandout |= 0x18  				# start bit + single-ended bit        commandout <<= 3    				# we only need to send 5 bits here        for i in range(5):                if (commandout & 0x80):                        GPIO.output(mosipin, True)                else:                        GPIO.output(mosipin, False)                commandout <<= 1                GPIO.output(clockpin, True)                GPIO.output(clockpin, False)        adcout = 0        # read in one empty bit, one null bit and 10 ADC bits        for i in range(12):                GPIO.output(clockpin, True)                GPIO.output(clockpin, False)                adcout <<= 1                if (GPIO.input(misopin)):                        adcout |= 0x1        GPIO.output(cspin, True)                adcout >>= 1       					# first bit is 'null' so drop it        return adcout# Code to connect a Ubidotstry:   api = ApiClient("75617caf2933588b7fd0da531155d16035138535") # Connect to Ubidots. Don't forget to put your own apikey      for curDs in api.get_datasources():						# Check if there's any Data Source with the name AirPi	if curDs.name == "AirPi":		dS = curDs		break   if dS is None:   	  dS = api.create_datasource({"name":"AirPi"})			# If doesn't exist it'll create a Data Source with the name Airpi     lightValue = getVarbyNames("Light_level",dS)   if lightValue is None:	  lightValue = dS.create_variable({"name": "Light_level","unit": "lux"}) # Create a new Variable for light   nitrogen = getVarbyNames("Nitrogen_dioxide_concentration",dS)   if nitrogen is None:	  nitrogen = dS.create_variable({"name": "Nitrogen_dioxide_concentration", "unit": "ppm"}) # Create a new Variable for NO2 level   mic = getVarbyNames("Noise_level", dS)   if mic is None:	  mic = dS.create_variable({"name": "Noise_level","unit": "mV"}) # Create a new Variable for noise level   carbon = getVarbyNames("Carbon_monoxide_concentration",dS)   if carbon is None:	  carbon = dS.create_variable({"name": "Carbon_monoxide_concentration","unit": "ppm"}) # Create a new Variable for CO level     temp = getVarbyNames("Temperature",dS)   if temp is None:	  temp = dS.create_variable({"name": "Temperature", "unit": "C"})	#Create a new Variable for temperature   humidity = getVarbyNames("Humidity",dS)   if humidity is None:	  humidity = dS.create_variable({"name": "Humidity","unit": "%"}) # Create a new Variable for humidityexcept:   print("Can't connect to Ubidots")while True:    # Code to get light levels data	light = readadc(0, SPICLK, SPIMOSI, SPIMISO, SPICS) # Read the analog pin where the LDR is connected	light = float(light)/1023*vin						# Voltage value from ADC	light = 10000/((vin/light)-1)						# Ohm value of the LDR, 10k is used as Pull up Resistor	light = exp((log1p(light/1000)-4.125)/-0.6704)		# Linear aproximation from http://pi.gate.ac.uk/posts/2014/02/25/airpisensors/ to get Lux value		# Code to get audio levels from  20 hz frequency	signalMax = 0	signalMin = 1024 	startMillis = int(round(time.time()*1000))			# Time in milliseconds	while (int(round(time.time()*1000))-startMillis<50):    # Collect data for 20hz frequency, 20hz=1/50ms    		noise = readadc(4, SPICLK, SPIMOSI, SPIMISO, SPICS) # Read the analog input where the mic is connected		if (noise < 1024):			if(noise > signalMax):				signalMax = noise			elif(noise < signalMin):				signalMin = noise	peakToPeak = signalMax - signalMin	print peakToPeak					# Peak to Peak value	db = float((peakToPeak*vin*1000)/1023)			#Measure in mV	time.sleep(0.1)		# Code to read NO2 and CO concentrations	no2 = readadc(2, SPICLK, SPIMOSI, SPIMISO, SPICS)	# Read the analog input for the nitrogen value		no2 = float(no2)/1023*vin								# Voltage value from the ADC	no2 = ((10000*vin)/no2)-10000							# Ohm value of the no2 resistor, 10k  is used as pull down resistor 	no2 = float(no2/700)					#Reference value	time.sleep(0.1)		co = readadc(3, SPICLK, SPIMOSI, SPIMISO, SPICS)		# Read the analog input for the carbon value	co = float(co)/1023*vin 								# Voltage value from the ADC	co = ((360000*vin)/co)-360000							# Ohm Value of the co resistor, 360k is used as pull down resistor	co = float(co/30000) 					#Reference value	# Code to use the DHT sensor	hum, temperature = Adafruit_DHT.read_retry(sensor, 4)	if hum is not None and temperature is not None:        	print 'Temp={0:0.1f}*C  Humidity={1:0.1f}%'.format(temperature, hum)	else:        	print 'Failed to get DHT sensor reading. Try again!'		# Print sensor values to the console 	print "light[lux]:", light	print "no2[ohm]:", no2	print "co[ohm]:", co	print "noise[mv]", db 	# Post values to Ubidots	lightValue.save_value({'value':light})	nitrogen.save_value({'value':no2})	mic.save_value({'value':db})	carbon.save_value({'value':co})		temp.save_value({'value':temperature})	humidity.save_value({'value':hum})GPIO.cleanup()						# Reset the status of the GPIO pins

view rawAirpi.py hosted with ❤ by GitHub

Finally, run the code:

sudo python airpi.py

This script creates a data source called "AirPi" inside your Ubidots account, as well as individual variables for each sensor. Then it will continuously post the envirnomental data to Ubidots.

Now visit your Ubidots account and you will find the live data from the AirPi!

Once your data is in Ubidots, you can create a real-time dashboard, SMS/Email alerts (i.e "Shoot me an Email when the CO concentration is too high!") or read the data through our API in order to build more advanced applications.

Here's another cool project to create a real-time map without writing any web code:

Do you have sensor applications in mind? click below to get started.

Originally published on Ubidots Blog on July 16, 2014. 

Did this answer your question?