AriPi and Ubidots
IoT Projects

Hands on the AirPi Kit v1.4, a weather station using Raspberry Pi

AirPi is a 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.

Once the AirPi is plugged to Ubidots, you’ll be able to create a real-time widget in Ubidots Dashboard.

Results: Using a Raspberry Pi Model B we can display these actually environmental details outside our office. With Ubidots, you can monitor your environments.

AIRPI AND UBIDOTS

Materials

raspberry_pi-1

  • USB WiFi Dongle

donglewifi

  • Airpikit v1.4

Airpiv1.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 measurement)
  • BMP085 (pressure, temperature)

Welding

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

Coding your Raspberry Pi

Before we can start coding we’ll need to fulfill some requirements:

When ready, log in 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 python
import time 						# Library for delays
import RPi.GPIO as GPIO 			# Library for using the GPIO ports
from  math import log1p,exp,log10 	# Library for math functions. No need for it if you'll get the raw data from the sensors
from ubidots import ApiClient  		# Ubidots Library
import 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 MCP3008

SPICLK = 18
SPIMISO = 24
SPIMOSI = 23
SPICS = 25

GPIO.setmode(GPIO.BCM) 				# Set up BCM as numbering system for inputs
GPIO.setup(SPIMOSI, GPIO.OUT)		# Configure the SPI I/O
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPICS, GPIO.OUT)

# Setup Variables

dS = None 							# Ubidots Data source. We'll call Airpi
sensor = 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.DHT22
light = 0 							# Save  value of the LDR
noise = 0 							# Save value of the Mic in
no2 = 0 							# Save value for Nitrogen dioxide level
co = 0 								# Save value for Carbon monoxide level
hum = 0 								# Save value for Humidity
temperature = 0 						# Save value for Temperature
vin = 3.3  							# Voltage reference for the ADC    

# Function to verify if the variable exists or not in your Ubidots account

def getVarbyNames(varName,dS):
	for var in dS.get_variables():
		if var.name == varName:
			return var
	return None

# Function from Adafruit to read analog values

def 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 Ubidots

try:
   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 humidity

except:
   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

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; you should see the live data from the AirPi!

Airpiout

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 here to get started today!