Flask Server with GPIOs

Let’s say that you have a running Flask server and you want your user to control the state (on/off) of an LED via the GPIO. The following technique shows how to connect Flask server with a separate GPIO script using PID.

Download the whole project

Run the following two scripts at the same time using the terminal:

from flask import *
import os
import signal

app = Flask(__name__)

#create a route path for index page
@app.route("/")
def index():
    return render_template("index.html")

#create a route path for about page
@app.route("/about")
def about():

    if 'name' in session: #if session 'name' exists
        print(session['name']) #print what's inside session[name]

        session.pop('name',None) #after printing, delete session name

    return render_template("aboutus.html") #render the html template aboutus

#/students accepts a get and post requests
@app.route("/student",methods=['GET','POST'])
def student():
    if(request.method == 'POST'): #if user fills a form
        studentName = request.form['studentname']
        if(studentName == "jimmy"):
            session["name"] = studentName #create session, name it 'name' and fill with studentName
            return redirect(url_for("about")) #redirect to about page
        else:
            return render_template("student.html") #render student template

    else:
        return render_template("student.html")#render student template

#routes with paramaters
@app.route("/led")
@app.route("/led/<param>")
def led(param=None):
    if(param == "on"): #if paramater is /led/on
        #read process id from text file generated by ledscript.py
        fh=open("processid.txt","r")
        processId = int(fh.read()) #load the process id
        fh.close()

        fh=open("led.txt","w")
        fh.write("1") #save 1 in text file. 1 means LED ON. 0 means LED Off
        fh.close()

        #send signal to process id
        os.kill(processId, signal.SIGUSR1)
        return "LED ON"
    elif(param =="off"): # if paramater is /led/off
        #read process id from text file
        fh=open("processid.txt","r")
        processId = int(fh.read())
        fh.close()

        fh=open("led.txt","w")
        fh.write("0")
        fh.close()

        #send signal to process id (ledscript)
        os.kill(processId, signal.SIGUSR1)
        return "LED OFF"
    else:
        return "LED MAIN PAGE"

if __name__ == "__main__":
    app.secret_key = 'asdfd!45sdf' #create secret key to secure sessions
    app.run(debug=True, host = "0.0.0.0")

import RPi.GPIO as GPIO
import time
import traceback
import os
import signal

def Main():
    try:
        #when scripts runs create processid.txt
        fh=open("processid.txt","w")
        fh.write(str(os.getpid())) #get current process id and store in file
        fh.close()

        GPIO.setmode(GPIO.BCM)

        GPIO.setwarnings(False)

        GPIO.setup(4, GPIO.OUT, initial = GPIO.LOW) #setup GPIO4 to low

        def handUSR1(signum,frame): #this function is automatically triggered from flask
            fh=open("led.txt","r")
            led = int(fh.read())
            fh.close()

            if(led == 0): #if 0 is found in text file
                print("LED OFF") #turn off led
                GPIO.output(4,GPIO.LOW)
            else:
                print("LED ON") #if not 0 (1) is found in text file
                GPIO.output(4,GPIO.HIGH) #turn on led

        signal.signal(signal.SIGUSR1,handUSR1) #callback function for SIGUSR1 signal (from flask when kill command is given)

        while(True):
            time.sleep(1)

    except Exception as ex:
        traceback.print_exc()
    finally:
        GPIO.cleanup() #this ensures a clean exit

Main()

Control a separate running script from a Web Server (python)- RPi

Let’s say that you have a running Flask server and you want your user to control the state (on/off) of a motion sensor via the GPIO. The most complex way is to create a multi-threading script which handles the server and GPIO code.

Another approach is to separate the server script from the GPIO script. Thus having two layers of scripts. This has the advantage to debug in isolation. For this technique one has to use Unix Signals which can be used to send signals from one process to another.

When you execute a script on your UNIX system, the system creates a process id (pid) which is different every time. A signal is a software interrupt which notifies a process with a significant event or request.

The following table gives a list of the most common signals:

NAME NUMBER DESCRIPTION
SIGHUP 1 Linux sends a process this signal when it becomes disconnected from a terminal.
SIGINT 2 Linux sends a process this signal when the user tries to end it by

pressing CTRL+C.

SIGILL 4 Linux sends a process this signal when it attempts to execute an illegal instruction.
SIGABRT 6 Linux sends a process this signal to the process when the process calls the ‘abort ()’ function
SIGFPE 8 Linux sends a process this signal when it has executed an invalid floating-point math instruction
SIGKILL 9 Linux sends a process this signal to end it immediately
SIGUSR1 10 User programs can send this signal to other process
SIGUSR2 12 User programs can send this signal to other process
SIGSEGV 11 Linux sends a process this signal when the program has attempted an invalid memory access
SIGPIPE 13 Linux sends a process this signal when the program has attempted to access a broken data stream, such as a socket connection that has been already closed
SIGALRM 14 A process can receive this signal from the Linux using the function alarm (), after a time period mentioned in its argument.
SIGTERM 15 Linux sends a process this signal requesting it to terminate
SIGCHLD 17 Linux sends a process this signal when a child process exits
SIGXCPU 24 Linux sends a process this signal when it exceeds the limit of

CPU time that it can consume.

SIGVTALRM 26 A process can receive this signal from the Linux using the function setitimer (), after a time period mentioned in its argument.

We are interested in SIGUSR1 and SIGUSR2 which can be used to send user signals.

Step 1:

First create the server layer (app.py). Documentation about Flask server can be found here.


from flask import *
import os
import signal

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/trigger1')
def process1():
    #read process id from text file
    fh=open("processid.txt","r")
    processId = int(fh.read())
    fh.close()

    #send signal to process id
    os.kill(processId, signal.SIGUSR1)

    return render_template('trigger1.html')

@app.route('/trigger2')
def process2():
    #read process id from text file
    fh=open("processid.txt","r")
    processId = int(fh.read())
    fh.close()

    #send signal to process id
    os.kill(processId, signal.SIGUSR2)

    return render_template('trigger2.html')

if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0')

Step 2:

Create the SignalReceiver.py script (you can modify this to control the GPIOs)


import os
import signal
import time

fh=open("processid.txt","w")
fh.write(str(os.getpid())) #get current process id and store in file
fh.close()

def handUSR1(signum,frame):
    print('triggered',signum)

def handUSR2(signum,frame):
    print('triggered',signum)

signal.signal(signal.SIGUSR1,handUSR1) #callback function for SIGUSR1 signal
signal.signal(signal.SIGUSR2,handUSR2) #callback function for SIGUSR2 signal

while(True):
    time.sleep(1)
    print("Waiting for signal")

Step 3: Run Server

flaskupload3.JPG

Step 4: Run SignalReceiver.py

flaskupload4.JPG

Step 5: 

In the browser, click Trigger 1 and Trigger 2 hyperlink buttons. Notice that SignalReceiver.py outputs ‘triggered 10′ and ‘triggered 12′. This means that both signals were sent and received correctly.

flaskupload5

Link to project: https://sourceforge.net/projects/pi-send-signals-to-scripts/

PIXEL(Raspbian)-Virtual Box-Persistence Drive

Please note that this is not officially approved by the PI team but the MagPi magazine offers a similar tutorial using a pendrive.

Step 1

Download the Pixel (Jessie Raspbian) image file: http://downloads.raspberrypi.org/pixel_x86/images/pixel_x86-2016-12-13/2016-12-13-pixel-x86-jessie.iso

Step 2:

Open Virtual Box, press new and create the following settings:

step1

Press Create and enter the following settings

step2

Press Start

step3

 

Step 3:

Browse to the downloaded ISO file and press Start

step4

Pixel is loaded

step5.JPG

Step 4:

To test persistence, create a new folder on your desktop and restart your OS.

step6

step7

Once your OS is restarted, you will notice that the folder you created is lost. This is because there is no persistence drive present.

step8.JPG

Step 5 (to create persistence drive):

Open terminal window and enter sudo apt install gparted

step9.JPG

When installation is finished, enter sudo gparted

step10.JPG

Click on Device > Create Partition Table and press Apply

step11.JPG

Right Click on the unallocated partition and press New

step13.JPG

Enter label name persistence with the following default settings and press Add

step14

Press the green very good sign and press Apply to any warning messages

step15

Press Close and close everything

step16

Now we are going to copy  the whole operating system from the virtual optical drive to
the hard drive.

Open the terminal window and enter sudo dd if=/dev/sr0 of=/dev/sda bs=1M

step17

Close the virtual machine (shutdown the OS)

Step 6:

Create a new Virtual Machine with the following settings. It is very important that you use your previously created virtual hard disk file. Do no create a new virtual hard disk.

 step18

Step 7:

Start your new machine and create a new python script to test persistence. I saved my file in the desktop. Restart your OS.

step19

Step 8:

Test file is still there. Persistence worked 🙂

step20

References:

Screen Sky – Android App

Download my new Android App – Screen Sky

screenshot1

screenshot2

– This app changes your wallpaper automatically every 60 minutes according to the weather. Weather data is collected from openweathermap.org by using your GPS location.

– You can also upload your pictures or take photos and tag them with weather and time conditions.

– Default app pictures and uploaded photos can be deleted by a long click on the respective image.

– Notifications are pushed when no wallpapers are found under respective weather and time status.

Maltese Online Radio – Raspberry Pi

So here’s the story:

  1. I woke up to Mum complaining that she can’t listen any longer to the radio from our kitchen due to noise interferance
  2. My brother suggested of buying an online radio
  3. I said “No..I can build one using the Raspberry Pi 2 and Music Player Daemon”
  4. I expected some excitement from their end but they just replied “ok”. Sad.
  5. Using the terminal I installed the player:
sudo apt-get install mpd mpc
  1. Changed the audio output to the headphone jack: https://www.raspberrypi.org/documentation/configuration/audio-config.md
  2. In the terminal I added some local radio stations using the command mpc add. I used Chrome’s Developer Tools(f12) to get these links:
Classic FM  mpc add http://media-ice.musicradio.com/ClassicFMMP3
Radio Malta 1 mpc add http://5.135.154.91:6982/
One Radio mpc add http://162.252.85.85:8202/stream/1/
Radio Malta 2 mpc add http://37.59.37.139:4954/
Magic Malta mpc add http://s46.myradiostream.com:6076
Radio 101 mpc add http://stream.vanilla.net.mt:8000/Title1=Radio%20101Length1=-1Version=2
Radju Marija mpc add http://dreamsiteradiocp2.com:8096
bay radio mpc add http://s1.voscast.com:8132
bay easy mpc add http://s1.voscast.com:8154
bay retro mpc add http://s1.voscast.com:8156
Campus FM mpc add mms://stream.um.edu.mt/CampusFM
RTK FM mpc add http://stardust.wavestreamer.com:3328/Live
Vibe FM mpc add http://s9.voscast.com:7824/ 
Bkara FM mpc add http://majestic.wavestreamer.com:8209/Live 
  1. From Ebay, I bought: 16 x 2 LCD Keypad Kit + DIY Transparent Acrylic Case For Raspberry Pi. I selected this product because it comes with 5 buttons and a case. http://www.ebay.co.uk/itm/New-16-x-2-LCD-Keypad-Kit-DIY-Transparent-Acrylic-Case-For-Raspberry-Pi-/112058244362?_trksid=p2047675.l2557&ssPageName=STRK%3AMEBIDX%3AIT&nma=true&si=D01jYFjgSMSs6rfWdX2eA1IH%252F%252Bo%253D&orig_cvip=true&rt=nc
  1. When the product arrived, I attached the LCD on the Pi. No soldering is required. It’s very easy. Just place the LCD board in the respective GPIOs.
  2. Followed this tutorial to enable I2C (with Raspi Config) – https://learn.adafruit.com/adafruits-raspberry-pi-lesson-4-gpio-setup/configuring-i2c
  3. Continued the setup : https://learn.adafruit.com/adafruit-16×2-character-lcd-plus-keypad-for-raspberry-pi/usage
  4. Installed the following library (can be done in step 10): https://github.com/adafruit/Adafruit_Python_CharLCD
  5. Programmed the following code (Buttons Up&Down = Volume Control; Buttons Left/Right = Skip radio; Button Select – Turn off Pi) :
#!/usr/bin/python
# Example using a character LCD plate.
import time
import Adafruit_CharLCD as LCD
import traceback
import subprocess
import os.path

# Initialize the LCD using the pins
lcd = LCD.Adafruit_CharLCDPlate()
# create some custom characters
lcd.create_char(1, [2, 3, 2, 2, 14, 30, 12, 0])
lcd.create_char(2, [0, 1, 3, 22, 28, 8, 0, 0])
lcd.create_char(3, [0, 14, 21, 23, 17, 14, 0, 0])
lcd.create_char(4, [31, 17, 10, 4, 10, 17, 31, 0])
lcd.create_char(5, [8, 12, 10, 9, 10, 12, 8, 0])
lcd.create_char(6, [2, 6, 10, 18, 10, 6, 2, 0])
lcd.create_char(7, [31, 17, 21, 21, 21, 21, 17, 31])

#turn on green light
lcd.set_color(0.0, 0.0, 1.0)
lcd.clear()
lcd.message("connecting: \n")

message = ""

def isConnected():
    global lcd
    while True: #keep repeating until internet connection is found
        try:
            ip = subprocess.check_output("hostname -I",shell=True)
            ip = ip[:3]
            if ip != "192":
                counter = 0
                while True:
                    print 'trying to connect to internet'
                    lcd.clear()
                    lcd.message("connecting to\n internet")
                    time.sleep(1)
                    remote_server = "8.8.8.8"
                    status = subprocess.call(['ping','-c','1',remote_server])#test connection with google
                    if(status == 0):
                        lcd.clear()
                        startPlaying()
                        break
                    else:
                        counter +=1

                    if(counter > 3):
                        break
            else:
                break
        except:
            pass

def startPlaying():
    global lcd
    lcd.clear()
    subprocess.call("mpc stop ",shell=True)
    subprocess.call("mpc play ",shell=True) #start player
    updateCurrentStation()
    lcd.clear()

def updateCurrentStation():
    global message
    time.sleep(0.2)
    message = subprocess.check_output('mpc current',shell=True)
    message = updateStationName(message.strip())
    if(len(message) > 15):
        message = message[:16] + '\n' + message[16:30]

def updateStationName(message): #this function updates those station name that are not returning a proper name
    if(message == "http://stream.vanilla.net.mt:8000/Title1=Radio%20101Length1=-1Version=2"):
        message = "101"
    elif(message == "http://162.252.85.85:8202/stream/1/"):
        message = "One Radio"
    elif(message == "http://majestic.wavestreamer.com:8209/Live"):
        message = "Bkara FM"
    elif(message == "http://stardust.wavestreamer.com:3328/Live"):
        message = "RTK"
    elif(message == "http://media-ice.musicradio.com/ClassicFMMP3"):
        message = "Classic FM"
    return message

def checkStatus():
    status = subprocess.check_output('mpc status',shell=True)
    if(status[0:6] == 'volume'): #empty status starts with text volume
        startPlaying()

def Main():

    global lcd
    global message
    cache_oldmessage = ""

    try:

        # Make list of button value, text, and backlight color.
        buttons = ( (LCD.SELECT, 'Select', (1,1,1)),
                    (LCD.LEFT,   'Left'  , (1,0,0)),
                    (LCD.UP,     'Up'    , (0,0,1)),
                    (LCD.DOWN,   'Down'  , (0,1,0)),
                    (LCD.RIGHT,  'Right' , (1,0,1)) )

        while True:
            isConnected()
            updateCurrentStation()

            # Loop through each button and check if it is pressed.
            for button in buttons:
                if lcd.is_pressed(button[0]):

                    if(button[0] == LCD.LEFT):
                        print("left button")                       

                        lcd.clear()
                        lcd.message("connecting:\n ")
                        subprocess.call("mpc next ",shell=True)
                        checkStatus()
                        updateCurrentStation()

                    elif(button[0] == LCD.RIGHT):
                        print("right button")

                        lcd.clear()
                        lcd.message("connecting: \n")
                        subprocess.call("mpc prev ",shell=True)
                        checkStatus()
                        updateCurrentStation()

                    elif(button[0] == LCD.UP):
                        subprocess.call("mpc volume +5" ,shell=True)
                        print("volume increased")

                    elif(button[0] == LCD.DOWN):
                        subprocess.call("mpc volume -5" ,shell=True)
                        print("volume decreased")

                    elif(button[0] == LCD.SELECT):
                        lcd.set_color(0.0, 1.0, 1.0)
                        lcd.clear()
                        lcd.message('Goodbye...')
                        time.sleep(2.0)
                        lcd.clear()
                        lcd.set_color(0.0, 0.0, 0.0)

                        subprocess.call(['poweroff'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

                    time.sleep(0.75) #button click delay

            if(cache_oldmessage != message):
                lcd.clear()
                lcd.message(message)
                cache_oldmessage = message

    except Exception as ex:
        traceback.print_exc()
        lcd.set_color(1.0, 0.0, 0.0)
        lcd.clear()
        lcd.message("error")

Main()

  1. Followed the following tutorial to launch the python script automatically on start-up: https://www.dexterindustries.com/howto/auto-run-python-programs-on-the-raspberry-pi/
  2. If you are having mpc connection timeouts with newest raspbian versions, just follow the fix by user csrlima in the following forum: https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=159485
  3. Tested the radio. Like a boss 🙂

unnamed-1

Raspberry Pi GPIO Emulator

This Raspberry Pi emulator simulates some of the functions used in the RPi.GPIO library (using python). The intention of this library is educational.

GPIO_Emulator

Installation

The easiest way is to download the zip file and extract the files in the same working environment of your script. To use the emulator just type the following at the beginning of your script.

from EmulatorGUI import GPIO

Simulation

This library simulates the following functions which are used in the RPi.GPIO library.

  • GPIO.setmode()
  • GPIO.setwarnings()
  • GPIO.setup()
  • GPIO.input()
  • GPIO.output()

Test Example


from EmulatorGUI import GPIO
#import RPi.GPIO as GPIO
import time
import traceback

def Main():
    try:
        GPIO.setmode(GPIO.BCM)

        GPIO.setwarnings(False)

        GPIO.setup(4, GPIO.OUT)
        GPIO.setup(17, GPIO.OUT, initial = GPIO.LOW)
        GPIO.setup(18, GPIO.OUT, initial = GPIO.LOW)
        GPIO.setup(21, GPIO.OUT, initial = GPIO.LOW)
        GPIO.setup(23, GPIO.IN, pull_up_down = GPIO.PUD_UP)
        GPIO.setup(15, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
        GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)
        GPIO.setup(26, GPIO.IN)

        while(True):
            if (GPIO.input(23) == False):
                GPIO.output(4,GPIO.HIGH)
                GPIO.output(17,GPIO.HIGH)
                time.sleep(1)

            if (GPIO.input(15) == True):
                GPIO.output(18,GPIO.HIGH)
                GPIO.output(21,GPIO.HIGH)
                time.sleep(1)

            if (GPIO.input(24) == True):
                GPIO.output(18,GPIO.LOW)
                GPIO.output(21,GPIO.LOW)
                time.sleep(1)

            if (GPIO.input(26) == True):
                GPIO.output(4,GPIO.LOW)
                GPIO.output(17,GPIO.LOW)
                time.sleep(1)

    except Exception as ex:
        traceback.print_exc()
    finally:
        GPIO.cleanup() #this ensures a clean exit

Main()

Download

Click here to download

Christmas Tree Controller

This is a brief explanation how to create a Christmas tree that its LEDs are controlled by the end user from a website. The concept is pretty simple. We need to have a server, a website, a database, a relay, LEDs and of course a Netduino. Obviously this concept can be applied on a RaspberryPi.

Video Demonstration

General Setup

For this project Node.JS was chosen because it has a popular library called Socket.IO and can be easily connected with MongoDB. Socket.IO is a JavaScript library for real time web applications. It enables real-time communication between web clients and servers. MongoDB is a cross-platform document-oriented database which is classified as a NoSQL database. Socket.IO was used to display the Christmas tree’s animation state (controlled by netduino) in real time to all connected users via Node.JS. MongoDB was used to store the user’s LEDs animation.

Here is a step-by-step breakdown structure of what was done:

Step 1 – User enters animation sequence: Selected LED colours with duration in seconds.

Step 2 – Upon submission, the user’s data is stored in MongoDB and emitted via Socket.IO to all connected clients in JSON.

Step 3 – Netduino checks every two seconds with Node.JS if there’s a new animation for playing. If there is, Node.JS gets the data from the database and returns it to Netduino as JSON string. Then Netduino parses the JSON string and plays the animation. Once it finishes, it instructs Node.js to get the next animation.

Step 4 – Another challenging part was how to setup the relay with the batteries, LEDs and Netduino. The following tutorial was followed and implemented: http://www.instructables.com/id/Controlling-AC-light-using-Arduino-with-relay-modu/?ALLSTEPS

 

FrameworkChristmas