Introduction
I have been playing with Raspberry Pis and electronics a lot and my 4 year old son has occasionally come to my desk to play with the red, yellow and green LEDs by sticking them on breadboards. He called them "traffic lights", so I thought to myself, why not build something for him which does that for Christmas!
Here are the features of the device which I have decided:
- A mobile App controlled traffic light which can simulate the traffic light / pedestrian light sequences and can also be manually turned on/off
- Some practical features like a 20 characters x 4 rows screen which displays:
- Date and time
- Temperature and humidity
- A message which is controlled by the app (2 lines x 20 characters)
This tutorial aims to cover the following technologies:
- Simple Pi HTTP server using python and flask
- Superlight sqlite database running in Pi
- Reading temperature and humidity with Raspberry Pi using DHT22 sensor. Details here.
- Using a cheap 20x4 LCD display with i2C interface. Details here.
- Building a simple mobile app using Xamarin which send commands to the Pi HTTP server. I am going to use Xamarin Forms, which is a very handy cross platform (iOS/Android/Windows mobile) framework.
Here's the end result wrapped nicely with lego and the app.
Circuit Diagram
Since the 20x04 LCD needs 5V and Raspberry Pi accept 3.3V as digital input, a 3.3V / 5V logic converter is needed.
A large version is here.
Using the Code
2 processes have been developed to run in the Raspberry pi.
- weather.py - which is a finite loop which:
- fetches and displays temperature and humidity and saves them to database
- displays date and time on LCD
- displays IP address when it boots up, so the app can easily find it
- weatherwww.py - a flask python app which:
- listens to weather request commands, read from database and returns them
- listens to traffic light control commands
- listens to message display command and displays them on LCD
Let's assume the code will be run from /home/pi/weather.
Running weather.py
Lets start with weather.py, there are a few prerequisites to be installed.
The code assume you are running Raspbian Wheezy or above on your Raspberry Pi.
Older version might require a manual installation of python gpio library.
sudo apt-get install python-dev python-rpi.gpio
Adafruit_DHT
- library for reading temperature and humidity. Run below in Raspberry Pi to install the library. Full details can be found here.
sudo apt-get update
sudo apt-get install build-essential python-dev
sudo python setup.py install
- Install
sqlite3
- sqlite is a very light weight, file based SQL database.
sudo apt-get install sqlite3
Create the database file and table.
sqlite3 weather.db
In sqlite prompt, create the table:
sqlite> CREATE TABLE weather (timestamp DATETIME, temperature REAL, humidity REAL);
- Install tools needed for I2C 2004 display (or follow here for detail instructions):
Enable i2C:
sudo raspi-config
- Select “Advanced Options”.
- Select “I2C”.
- Select "Yes".
Install Utilities:
sudo apt-get update
sudo apt-get install -y python-smbus i2c-tools
Reboot:
sudo reboot
Connect up the i2C 2004 display by following the schematic diagram. Find the address of it by running the following command. For my case, I got 0x27.
sudo i2cdetect -y 1
Edit lcd_i2c.py to reflect the address you get:
#for 2004
I2C_ADDR = 0x27
At this stage, all prerequisites for running weather.py should now be ready. Try to run below (sudo
is required for gpio
access).
sudo python weather.py
If all goes well, you should see something similar to below in the 2004 LCD, showing the datetime, temperature, humidity and ip address (3rd row will show the eth0
and 4th row will show wlan0
).
Running weatherwww.py
weatherwww.py is a flask web application. Flask is a python framework which allows you to write webservices / dynamic webpages written in python easily and quickly. A quickstart guide is available.
To install flask, the quickest way to run command as below. You can also run it under virtualenv.
sudo pip install Flask
To run up weatherwww.py webapp under the built-in flask webserver, run below:
cd /home/pi/weather
export FLASK_APP=weatherwww.py
flask run --host=0.0.0.0
After running the above, It should say something like:
Using a browser, test if the flask webapp
is working (replace 192.168.11.115 with IP address of your Pi).
If it returns "OK", it means the webapp is up and running. The red LED should also be turned on if the electronics are all connected up.
The last step of the setup is to autostart the two processes by adding to rc.local by calling the Run scripts (I have included RunWeather and RunWeatherWWW in the zip)
<code>sudo nano /etc/rc.local</code>
Points of Interest
Quick Explanation of the Code - weather.py
When starts up, it fetches the temperature and humidity and inserts into database:
humidity, temperature = Adafruit_DHT.read_retry(sensor, 4)
InsertWeather(temperature,humidity)
Then attempts to fetch and display the IP on the screen (since we want to run this device headless):
lanip = GetLANIP().strip()
wanip = GetWLANIP().strip()
retry=0
while((not lanip) and (not wanip)) and retry<5:
time.sleep(2)
lanip = GetLANIP().strip()
wanip = GetWLANIP().strip()
retry = retry + 1
lcd_i2c.lcd_string(lanip,LCD_LINE_3)
lcd_i2c.lcd_string(wanip,LCD_LINE_4)
It will then enter an infinite loop, which continuously fetches the weather (every 10mins) and refreshes the time on display (around every 30 seconds depending on how long it takes to fetch the weather).
Quick Explanation of the Code - weatherwww.py
In flask, each URL is mapped to a method. For example:
@app.route('/redon')
def redon():
GPIO.output(GPIO_RED,True)
return 'OK'
There are also some slightly long running methods like this one. Since we are using the built in single threaded flask web container, it will accept any new request when the previous one is still running. To improve this, we can consider changing this to run async starting a new thread and returning response immediately. However, this gets a little trickly as newer requests will need to cancel previously running request.
@app.route('/blinkyellow')
def blinkyellow():
allledoff()
GPIO.output(GPIO_YELLOW,True)
time.sleep(1)
GPIO.output(GPIO_YELLOW,False)
time.sleep(1)
GPIO.output(GPIO_YELLOW,True)
time.sleep(1)
GPIO.output(GPIO_YELLOW,False)
time.sleep(1)
GPIO.output(GPIO_YELLOW,True)
time.sleep(1)
GPIO.output(GPIO_YELLOW,False)
return 'OK'
You may also try other url such as displaying the message on lcd like:
http://192.168.11.115:5000/display?line3=hello&line4=how are you?
In part 2, I will be talking about the Xamarin mobile app for remote controlling this device.