SQLite/Bottle Todo List

I wanted to do a Todo List web application that I could pass on to my kids to try. My goal was to give them an introduction to SQL, Web interfaces and Web templating.

For the Todo List application the Python Bottle Web Framework will be used. The Bottle library is a lightweight standalone micro web framework.

To store the Todo list items an SQLite database is used. SQLite is a file based server-less SQL (Structured Query Language) database which is ideal for small standalone applications.

Finally to build Web page, Python web templates will be used. The advantage of using web templates is that is reduces the amount of code written and it separates the presentation component from the backend logic.

 

Getting Started with Bottle

To install the Python bottle library:

pip install bottle

As a test we can make a program that has a home page (“/”) and a second page, then links can be put on each of the page to move back and forward.

todo_code_1

The @route is a decorator that links a URL call, like “/” the home page to a function. In this example a call to the home page “/” will call the home_page() function.

In the home_page() and pages2() functions the return call is used to pass HTML text to the web browser. The anchor tag (<a) is used to define page links.

The run() function will start the Bottle micro web server on: http://127.0.0.1:8080/

The output is below. 

SQLite

The Python SQLite library is one of the base libraries that is installed with Python.

SQLite has a number of tools and utilities that help manage your databases. One useful  light weight application is: DB Browser for SQLite. It is important to note that SQLite data can be view by multiple applications, but for edits/deletes only 1 application can be accessing SQLite.

For the Todo list we’ll start with a simple database structure using three fields:

  • Category – this a grouping such as: shopping, projects, activities etc.
  • theItem – this is the actual to do item
  • id – an unique index for each item. (This will used later for deleting rows)

The Todo database can be created with the SQLite Brower, or in Python code. The code below creates that database, adds a todo table and then inserts some records.


import sqlite3

print("Create a todo list database...")

conn = sqlite3.connect('todo.db') # Warning: This file is created in the current directory
conn.execute("CREATE TABLE todo (category char(50), theitem char(100),id INTEGER PRIMARY KEY )")
conn.execute("INSERT INTO todo (category, theitem) VALUES ('Shopping','eggs')")
conn.execute("INSERT INTO todo (category, theitem) VALUES ('Shopping','milk')")
conn.execute("INSERT INTO todo (category, theitem) VALUES ('Shopping','bread')")
conn.execute("INSERT INTO todo (category, theitem) VALUES ('Activities','snow tires')")
conn.execute("INSERT INTO todo (category, theitem) VALUES ('Activities','rack lawn')")
conn.commit()

print("Database todo.db created")

The DB Browser can be used to view the newly created database.

make_table

Viewing the Data in Python

An SQL SELECT command is used to get all the records in the todo database.  A fetchall() method is will return all the database rows in a Python tuple variable. Below is the code to write the raw returned data to a browser page.

# Send to raw SQL result to a Web Page
#
import sqlite3
from bottle import route, run

@route('/')
def todo_list():
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    
    c.execute("SELECT * FROM todo")
    result = c.fetchall()
    c.close()
# note: the SQL results are an array of data (tuple)
# send results as a string
    return str(result)

run()

todo_raw

The output formatting can be improved by adding a sort to the SQL SELECT statement and then HTML code are be used to show category heading.

todo_code_2

web_rbr

For small applications putting HTML code in the Python code is fine, however for larger web projects it is recommended that the HTML be separated out from the database or backend code.

Web Templates

Web templates allow you to separate the database and back end logic from the web presentation. Bottle has a built-in template engine called Simple Template Engine. I found it did everything that I needed to do. It’s possible to use other Python template libraries, such as Jinja, Mako or Cheetah, if you feel you need some added functionality.

The earlier Python code is simplified by removing the HTML formatting logic. A template object is created with a template name of  sometime.tpl). An example would be:

output = template(make_table0, rows=result, headings = sqlheadings)

Where rows and headings are variable names that are used in the template file. The template file make_table0.tpl is in the working directory.

#
# Build a To Do List with a Web Template
#
import sqlite3
from bottle import route, run, template


@route('/')
def todo_list():
    # Send the output from a select query to a template
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()    
    c.execute("SELECT * FROM todo order by category, theitem")
    result = c.fetchall()
    # define a template to be used, and pass the SQL results
    output = template('make_table0', rows=result)
    return output
        
run()

Templates are HTML pages with inline Python code. Python code can either be in blocks with a <% to start the block and a %> to end the block, or each line can start with %.

Two of the major differences of inline template Python code are:

  • indenting the line of Python is not required or used
  • control statements like : if and for need an end statement

A template that takes the SQL results and writes each row in a table would look like:

tpl_make_table

todo_tmp_table

A template that take the SQL results and writes a category heading and lists the items would look like:

tpl_make_list

web_tpl_rbr

Include ADD and DELETE to the Templates

The next step is to include ADD and DELETE functionality.

For the DELETE functionality, a form is added to the existing template. A ‘Delete’ button is placed beside all the Todo items and the button passes the unique index id (row[2]) of the item. The form has a POST request  with the action going to the page ‘/delete‘ on the Bottle Web Server.

For the ADD functionality, a new template is created and a %include call is put at the bottom of the main template. (You could also put everything in one file).

The main template now looks like:

tpl_show_todo

The new item template uses a dropdown HTML element with some predefined category options (Activities, Projects and Shopping). The item text will displace 25 characters but more can be entered. Pressing the save button will generate a POST request to the “/new” URL on the Bottle server.

The new_todo.tpl file is:

tpl_newtask

Bottle Python Code with /add and /delete Routes

The final step is to include routes for the /add and /delete URL references.

The new_item() function gets the category and Todo item from the form in the new_todo template. If the request passes a non-blank item (request.forms.get(“theitem”) then an SQL INSERT command will add a row. The unique item ID is automatically included because this field is defined as an index key.

The delete_item() function reads the unique item id that is passed from the button to issue an SQL DELETE statement.

At the end of the new_item() and delete_item() function the user is redirected back to the home (“/”) page.

#
# Build a Todo List 
#
import sqlite3
from bottle import route, run, template, request, redirect, post  

# The main page shows the Todo list, /new and /delete references are called from this page
@route('/')
def todo_list():
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    
    c.execute("SELECT * FROM todo order by category,theitem ")
    result = c.fetchall()
    # in case column names are required
    colnames = [description[0] for description in c.description]
    numcol = len(colnames)
    # for now only the rows=result variables are used
    output = template('show_todo', rows=result, headings=colnames, numcol = numcol)
    return output

# Add new items into the database
@route('/new', method='POST')
def new_item():

    print("New Post:", request.body.read())
    theitem = request.forms.get("theitem")
    newcategory = request.forms.get("newcategory")

    if theitem != "":        
        
        conn = sqlite3.connect('todo.db')
        c = conn.cursor()
        c.execute("INSERT INTO todo (category,theitem) VALUES (?,?)", (newcategory,theitem))
        conn.commit()
        c.close()

    redirect("/") # go back to the main page   

# Delete an item in the database
@route('/delete', method='POST')
def delete_item():

    print("Delete:", request.body.read() )
    theid = request.forms.get("delitem").strip()
    print("theid: ", theid)
               
    conn = sqlite3.connect('todo.db')
    c = conn.cursor()
    sqlstr = "DELETE FROM todo WHERE id=" + str(theid)
    print(sqlstr)
    c.execute(sqlstr)
    conn.commit()
    c.close()

    redirect("/") # go back to the main page   
        
run()

The application will look something like:

todo_final

Final Clean-up

Some of the final clean-up could include:

  • enlarge the database to include fields like: status, due date, who is responsible etc.
  • add an “Are you sure?” prompt before doing adds and deletes
  • verify double entries aren’t included
  • include an edit feature
  • make the interface slicker

If you want to speed up the performance PyPy can be used instead of the Python interpreter. To use Pypy (after you’ve installed it), you will need to install the pip and bottle:

pypy3 -m ensurepip --user
pypy3 -mpip install bottle --user

Final Comments

As I was working on this I found a good BottleTutorial: Todo-List Application. This tutorial approaches the Todo list project differently but it is still a worthwhile reference.

SVG Web Animation

There are a number of good Web animation techniques that are available. Flash animation support is being discontinued in 2020, but luckily there are some good alternatives, such as HTML 5 Canvas, Scalar Vector Graphics (SVG),  and even CSS (Cascading Style Sheets) can be used .

HTML 5 Canvas draws 2D graphics, on the fly with a JavaScript. The canvas is rendered pixel by pixel. In canvas, once the graphic is drawn, it is forgotten by the browser. If its position should be changed, the entire scene needs to be redrawn, including any objects that might have been covered by the graphic.

SVG is a language for describing 2D graphics in XML, which means that every element is available within the SVG DOM. In SVG, each drawn shape is remembered as an object. If attributes of an SVG object are changed, the browser can automatically re-render the shape.

In this blog I wanted to document my SVG testing.

Using SVG

SVG can be used inline within an HTML document. Below is an example with a rectangle, circle and some text.

<!DOCTYPE html>
<html>
<body>

<svg width="400" height="400">
  <rect width="100" height="100" fill= "blue" />
  <circle cx="150" cy="50" r="40" fill="green" />
  <text x="10" y="120" fill="red">SOME SVG TEXT</text>
</svg>

</body>
</html>

This will generate a web like:

svg1

An SVG element has a width and height property and all the drawing elements are positioned within this area.

Dynamic SVG Bar

A bar can be created using a rectangle () element. Javascript is used to dynamically adjust the top and height of the rectangle.

<!DOCTYPE html>
<html>
<head>
<script type="text/JavaScript">

setTimeout(updatebar, 2000);

function updatebar() {
// 
  var newvalue = (Math.random() * 300); // get a random integer 0-100
  if (newvalue > 250) {
    document.getElementById("bar1").style.fill = "red";
  } else {
    document.getElementById("bar1").style.fill = "green";
  }
  newvalue = Math.round(newvalue);
  var newheight = newvalue.toString();
  var num = 300 - newvalue - 5;
  var newy = num.toString();  

  document.getElementById("bar1").setAttribute("height",newheight);
  document.getElementById("bar1").setAttribute("y",newy);
  document.getElementById("bartext").innerHTML = "value: " + newheight ;
  setTimeout(updatebar, 2000);
}
</script>
</head>
<body>
<h2> SVG Bar Example</h2>
<svg width="400" height="400" >
  <rect x="0" y="0" width="160" height="300" style="fill:white;stroke:black;stroke-width:4;" />
  <rect id="bar1" x="5" y="145" width="150" height="150" style="fill:green;stroke:black;stroke-width:2;" /> 
  <text id="bartext" x=30 y = 320 style="font-family:verdana;font-weight:bold">value: 50 </text>
</svg>

</body>
</html>

svg_bar

Animate Graphics

There some SVG drawing packages such as: https://www.drawsvg.org/drawsvg.html

There are also some free libraries, I used: https://www.opto22.com/support/resources-tools/demos/svg-image-library to animate a flow valve.

I needed to do a little bit of trial and error but I was able to add a text element to the bottom of the SVG that could be animated with Javascript. Below is the SVG file:

<svg x="0px" y="0px" viewBox="0 0 100 100" xml:space="preserve"><svg><g>
<g id="shape">
  <circle fill="#999999" cx="50.093" cy="32.75" r="32.75"></circle>
  <rect x="0.176" y="71.667" fill="#999999" width="99.833" height="26.833"></rect>
  <rect x="44.926" y="63" fill="#999999" width="10.333" height="10.5"></rect>
  <rect y="70" fill="#999999" width="4.5" height="30"></rect> 
  <rect x="95.509" y="70" fill="#999999" width="4.5" height="30"></rect>
</g>
<g id="linear">
  <linearGradient class="linear" id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="50.0926" y1="94.5113" x2="50.0926" y2="75.6554">
    <stop offset="0" style="stop-color:#E6E6E6"></stop>
    <stop offset="1" style="stop-color:#000000"></stop>
  </linearGradient>
  <polygon class="linear" fill="url(#SVGID_1_)" points="70.031,75.655 60.041,79.079 40.144,79.079 30.154,75.655 0.176,75.655 0.176,94.511 
    29.289,94.511 40.144,90.791 60.041,90.791 70.896,94.511 100.009,94.511 100.009,75.655   ">
</g>
<g id="light">
  <circle fill="#E6E6E6" cx="50.093" cy="32.75" r="29.074"></circle>
  <path fill="#E6E6E6" d="M44.833,71.5v-6.409c0.606,0.096,1.217,0.179,1.833,0.241V71.5H44.833z"></path>
</g>
<g id="hlight">
  <path fill="#FFFFFF" d="M18.343,33.75C18.343,15.663,33.005,1,51.093,1c8.789,0,16.763,3.469,22.646,9.104
    C67.777,3.881,59.391,0,50.093,0c-18.087,0-32.75,14.663-32.75,32.75c0,9.298,3.881,17.685,10.104,23.646
    C21.812,50.514,18.343,42.539,18.343,33.75z">
  <rect x="26.093" y="21.474" fill="#FFFFFF" width="48" height="23.053"></rect>
</g>
<g id="shadow">
  <path fill="#000000" d="M72.738,9.104c5.635,5.882,9.104,13.857,9.104,22.646c0,18.087-14.663,32.75-32.75,32.75
    c-8.789,0-16.763-3.469-22.646-9.104C32.408,61.619,40.795,65.5,50.093,65.5c18.087,0,32.75-14.663,32.75-32.75
    C82.843,23.452,78.961,15.066,72.738,9.104z">
  <path d="M55.259,71.5v-6.409c-0.606,0.096-1.217,0.179-1.833,0.241V71.5H55.259z"></path>
  <polygon points="27.235,22.589 74.093,22.589 74.093,21.474 26.093,21.474 26.093,44.526 27.235,44.526  "></polygon>
  <path d="M22.018,33.75c0-16.057,13.017-29.074,29.074-29.074c7.774,0,14.83,3.057,20.047,8.028
    c-5.296-5.558-12.764-9.028-21.047-9.028c-16.057,0-29.074,13.017-29.074,29.074c0,8.283,3.469,15.751,9.028,21.047
    C25.076,48.58,22.018,41.524,22.018,33.75z">
</g>
</g>
<text id="flowval" name="flowval" x = "40" y = "40" fill= "green" style="font-family:verdana;font-weight:bold"> 00 </text></svg>
</svg>

External SVG files can be used in a Web page by:

  •  <img – as an image file. (Only good for static or self-contained SVG files)
  • <frame – as a frame.
  • <object – as a object reference within an existing web document
  • <embed – as an embedded element

Unfortunately I found that Chrome only supports inline SVG with Javascript. Microsoft Edge and Firefox worked with both the object and embed tags.

Below is the code that I used to animate the text on the flow valve:

<!DOCTYPE html>
<html>
<head>
<script type="text/JavaScript">

setTimeout(updatebar, 2000);

function updatebar() {
// 
  var randvalue = (Math.random() * 100); // get a random integer 0-100
  var flowvol = Math.round(randvalue.toString());
  // set the text in the svg object   
  var svgobj = document.getElementById("flowmeter");
  var svgdoc =  svgobj.getSVGDocument();
  svgdoc.getElementById("flowval").textContent =  flowvol ;
  
  setTimeout(updatebar, 2000);
}
</script>
</head>
<body>
<h2> SVG Flow Meter</h2>
<embed id="flowmeter" height= '50%' width='100%' src="flowmeter.svg" >

</body>
</html>

flowmeter_1

Final Comments

I found that it can be a little challenging to tweek existing SVG library examples. The browser “development tools” can be used to find and test SVG elements. Below is an example where I found the solar panel element that I need to animate.

svg_devtools

For 100% cross-browser capability it would be recommended to put all the SVG code in one document.

The next step will be to use a Raspberry Pi Web app and some AJAX calls to animate the data.

Streaming Video Server

There are some reasonably priced video surveillance products available on the market. If however you have a USB Web Cam and a Raspberry Pi (or equivalent or an old PC) you can make your own.

If you are working in the Unix world I would recommend motion , it’s super easy to setup and it’s got lots of added features if you want to turn them on. To install:

sudo apt-get install motion

Once you have motion installed you’ll need to tweek some of it’s parameters by:

sudo nano /etc/motion/motion.conf

The /etc/motion/motion.conf file contains a lot of cool parameters to tweek, some of the more important ones are:

# Image width (pixels). Valid range: Camera dependent, default: 352
width 800

# Image height (pixels). Valid range: Camera dependent, default: 288
height 600

# Maximum number of frames to be captured per second.
framerate 1

# Maximum framerate for stream streams (default: 1)
stream_maxrate 1

# Restrict stream connections to localhost only (default: on)
stream_localhost off

The speed of your hardware and network will determine how many frames per second you can use.

To run the video server enter:

sudo motion

The motion package has a built in web server that is accessed by: http://your_ip:8081

livevideo

Hardware Setup

There are lots of options for the mounting of your video server. I like to use Lego Pi cases about ($8) and then use some Lego to secure the rest of the components. Below is an example where I used a PIR (Pyroelectric Infrared) module ($3) to manually turn the motion software on/off, and I added a USB card reader to enable/disable the system.

OLYMPUS DIGITAL CAMERA
Homemade Security System

Performance and Tuning

Ideally it would be nice to run at 24 frames per second (or better) to get smooth video action. Unfortunately I found that the Raspberry Pi 3 would often freeze up at this refresh rate with a USB camera. The linux command line tool vmstat can be useful to show your CPU and I/O status. Below is some sample vmstat output:

$ vmstat # Pi 3 video server at 24 fps
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r b swpd free buff cache si so bi bo in cs us sy id wa st
 1 0 0 593552 17808 269856 0 0 41 57 803 180 7 1 74 18 0

The id is the idle time (74%), which isn’t bad. The problem however id wa, waiting for I/O.

You will have to do some trial and error to get a refresh rate that works best for you.

Port Forwarding

With the basic setup you will be able to access the video server from your local LAN/WAN. If however you want to access your video server from the Internet then you will need to allow a connection through your router to your video server, this is called port forwarding.

Unfortunately the configuration of port forwarding will vary from manufacturer to manufacture, so please see the documentation for your specific devices.

 

Python talking to littleBits Cloud API

LittleBits is a set of components that allow kids to build their own electrical circuits. The Cloudbit will send and receive values from the Internet.

For this project we wanted to build some Python programs that could interact with the littleBits Cloud API.

littleBits Hardware Setup

cloudbit_setup

The Cloudbit enables an input to be sent to the Internet, and it will receive a value (output) from the Internet. For a test setup we used a dimmer bit to adjust the input value with a number bit to show the value. On the output side we used a bargraph bit. Other combinations of bits are possible. The key is to be able to test and see your input and output values.

Cloudbits Setup

For the Cloudbit setup you will need to create a sign-in on the littleBits web site. For details on how to setup your Cloudbit use the following link.

Python Basic Setup

The Cloud API is a RESTful interface, that uses http requests with some header definitions. Before you get started you’ll need your specific littleBits device ID and authorization token. In your specific Cloudbit definition go to the Settings icon, and get your Device ID and AccessToken.

littlebit_id

 

The Cloud API presently does not support a single point read (this might change), instead the input data point value is streamed about once a second.

The basic syntax in Python to get values from the  Cloud API will be:

import requests

requests.packages.urllib3.disable_warnings()

# Change with your Authorization code and deviceID
authToken = "4f3830b44e15fa0d"
deviceId = "00e04c"

headers = {"Authorization": "Bearer " + authToken,"Content-type": "application/json"}

# For a read 
littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/input"
r = requests.get(littleBitsUrl, headers=headers, stream=True)

#  For a write, note: a data body needs to be defined
# littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/output"
# body = {"percent": thevalue , "duration_ms": thetime} 
# thebody = json.dumps(body)
# r = requests.post(littleBitsUrl, data=thebody, headers=headers)

To do a read of the Cloud API an get request is done, to do a write a post request is used.

Python Read Value Example

The cloud API will stream the input value about every second in a format something like:

data: {"type":"input","timestamp":1521587206463,"percent":61,"absolute":629,"name":"amplitude","payload":{"percent":61,"absolute":629},"from":{"device":{"id":"00e04c0379bb","mac":"00e04c0379bb"}}}
{"type":"input","timestamp":1521587206463,"percent":61,"absolute":629,"name":"amplitude","payload":{"percent":61,"absolute":629},"from":{"device":{"id":"00e04c0379bb","mac":"00e04c0379bb"}}}

This data stream will need to be massaged with the following steps:

  • decode the stream (UTF-8)
  • remove the leading data: , (the remain message will be JSON formatted).
  • load the remain string into a JSON object

Below is some example code, for an app with a slider.

lb_tk_input

#
# lb_input.py - read input from a Cloudbit device
#
import json
import requests

requests.packages.urllib3.disable_warnings()

# Change with your Authorization code and deviceID
authToken = "4f3830b44e1d4b27xxxxxx"
deviceId = "00e04c03xxxx"

littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/input"

headers = {"Authorization": "Bearer " + authToken,"Content-type": "application/json"}
r = requests.get(littleBitsUrl, headers=headers, stream=True)

for line in r.iter_lines():
   strmsg = line.decode("utf-8").strip()
 
   print("Str: ",strmsg)
   if len(strmsg) > 0:
      lb_data = strmsg.split('data:')[1]
      print(lb_data)
      result = json.loads(lb_data)
      thevalue = result['percent']
      lb_bar.set(thevalue)
      thetime = str(datetime.datetime.fromtimestamp(result['timestamp']/1000))
      lb_time['text'] = "Time : " + thetime[:-7]
      root.update()

The Cloud API passed the time stamp as a numeric value with microseconds. The time can be cleaned with:

thetime = str(datetime.datetime.fromtimestamp(result['timestamp']/1000)) 
time_no_micro_seconds = thetime[:-7]

Python Output Value Example

The Cloud API output uses a post method and unlike the input example there is no streaming.

The new output value and a pulse time is sent in the post data parameter. The value is from 0-100, and a pulse time is -1 for sustained, otherwise a millisecond pulse time is used.

Below is some sample code for a Tkinter app:

lb_tk_output

from Tkinter import *
import json
import requests

# update your auth Token and device ID
authToken = "4f3830b44e1d4b27xxxx"
deviceId = "00e04c03xxxxx"

littleBitsUrl = "https://api-http.littlebitscloud.cc/devices/" + deviceId + "/output"

headers = {"Authorization": "Bearer " + authToken, "Content-type": "application/json"}

def setvalue():
	thevalue = lb_value.get()
	thetime = lb_duration.get()
	body = {"percent": thevalue , "duration_ms": thetime}
	thebody = json.dumps(body)
	print body, thebody
	r = requests.post(littleBitsUrl,  data=thebody, headers=headers)
	print r
     

root = Tk()
root.title('littleBits Output')

Label(text = "Value (0-100) :",width=30).grid(row=0,column=0)
lb_value = Entry(root, width= 10)
lb_value.grid(row=0,column=1)
Label(text = "Duration (ms) (constant=-1) :",width=30).grid(row=1,column=0)
lb_duration = Entry(root, width= 10)
lb_duration.grid(row=1,column=1)


Button(root, text=' Set Output ', bg='silver', command=setvalue).grid(row=2,column=1)

root.mainloop()

Final Comments

There are a lot of simple applications and projects that can be created with Python and some littleBits. One of the limitations on the Cloudbit is that it only sends 1 value and receives 1 value. If you are dealing with digital signals it would be possible to do some multiplexing.

Pi PHP Controls

I’ve been trying to teach my kids PHP,  below are some notes on how to get a PHP page to control Pi GPIO outputs. For motor controls we use the Pimoroni ExplorerHat Pro and it is possible to address the ExplorerHat pins directly with gpio calls. However other shields or tops like PiFace Digital could also be used.

Loading PHP

On the Raspberry Pi you will need to load both a web server and PHP. There are a number of good web servers to load. We picked Apache because it is well documented and more mainstream.

There are some good installation procedure for installing Apache and PHP on the Raspberry Pi. A minimalist installation would be:

sudo apt-get install apache2 -y
sudo apt-get install php5 libapache2-mod-php5 -y

If everything is installed correctly the Apache home directory should be: /var/www/html.

To test that your installation is working open a browser on the Pi and go to: http://localhost. If the default (index.html) page comes up then you’ve install Apache correctly.

ExplorerHat Pro GPIO Pinouts

Typically we use the Python interface to talk to the ExplorerHat Pro. If you use PHP you will need to address the ExplorerHat Pro GPIO pins directly.

ExplorerHat  BCM wPi
Motor 1 Forward 19 24
Motor 1 Backward 20 28
Motor 2 Forward 21 29
Motor 2 Backward 26 25
LED 1 4 7
LED 2 17 0
LED 3 27 2
LED 4 5 21
Output 1 22 31
Output 2 26 32
Output 3 23 33
Output 4 27 36

PHP Interfacing to Pi GPIO

There are a few ways to access the GPIO pins in PHP:
1. use a PHP library
2. shell to the gpio command

Using a PHP library allows for a standard PHP interface, with an object model.

From testing I found that the PHP libraries were not as flexible as the standard gpio command. For example you could not access extended GPIO pin numbers (i.e. 200).

GPIO Command Line Utility

PHP can shell out to the gpio command line utility. I liked this approach because I could test the actions manually before putting them into a PHP web page.

A simple gpio read example would be:

<html lang="en">
<head>
</head>
<body>
<?php
$ret = shell_exec('gpio read 7');
echo "Pin 7 status = " . $ret;
?>
</body>
</html>

And a gpio write example (with reading back the result) would be:

<html>
<head>
</head>
<body>
<?php
exec("gpio write 7 1");
$ret = shell_exec('gpio read 7');
echo "Pin 7 status = " . $ret;
?>
</body>
</html>

 

PHP Forms

For many Pi projects button interfaces are all that is required. In the Web design this is not typical so it is important to determine which button is pushed. One approach to this problem is to give all the buttons the same name:


  
  
  
  


Then in the PHP code look for a value for this form variable:

<?php
// define the GPIO pins for the motor ouptput (Note: PiFace pins start at 200)
$leftpin = 24;
$rightpin = 29;

if (isset($_POST['submit'])) {
	switch ($_POST['submit']) {
		case "go":
			exec("gpio write " . $leftpin . " 1");
			exec("gpio write " . $rightpin . " 1");
			break;
		case "stop":
			exec("gpio write " . $leftpin . " 0");
			exec("gpio write " . $rightpin . " 0");
			break;
		case "left":
			exec("gpio write " . $leftpin . " 1");
			exec("gpio write " . $rightpin . " 0");
			break;
		case "right":
			exec("gpio write " . $leftpin . " 0");
			exec("gpio write " . $rightpin . " 1");
			break;
	}
}
?>

Mobile CCS Templates

There are quite a few good mobile templates to choose from. [Bootstrap](http://getbootstrap.com/) is one of the most popular frameworks, and for Pi applications it seems to be a good fit. A simple four button example would be:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>PHP/Pi Rover Controls</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">

  <h2>PI Four Button Example</h2>
  <form action="" method="post">
    <div class="form-group">

    <button type="submit" name="submit" class="btn-success btn-lg" style="width:100%" value="go">Forward</button>
    <button type="submit" name="submit" class="btn-info btn-lg" style="width:49%" value="left">Left</button>
    <button type="submit" name="submit" class="btn-info btn-lg" style="width:49%" value="right">Right</button>
    <button type="submit" name="submit" class="btn-danger btn-lg" style="width:100%" value="stop">Stop</button>
  </form>
</div>

</body>
</html>

Some of the key items are:

  • Add references in to the bootstrap ccs and js files
  • Add tags with the required class definitions:
    • the btn-lg class will make a large button, instead of standard sized btn 
    • different button colours are possible using btn-info, btn-success. btn-danger
    • Button width is defined with style=”width: xx%” . For multiple buttons the sum of the width needs to <100%

 

bootstrap4btns

Further Examples

Below are some pictures of a mobile rocket launcher project.  The Web page had two sections. The top section controlled bi-directional motors that were connected to a Explorer HAT Pro shield. The bottom section controlled the rocket launcher turret. The missile launcher was connected via a USB cable to the Pi. For the missile launcher program we created a Python app with command line options to set the action.

Screenshot

OLYMPUS DIGITAL CAMERA

Pi/Node-Red Car

The goal of the Pi/Node-Red car project was to create a small vehicle that can be controlled from a smart phone . For the project we used:

  • 1 Car chassis for Arduino ($15)
  • 1 Pimoroni Explorer HAT Pro  ($23)
  • 1 Portable microUSB charger
  • 1 USB WiFi Adapter
  • 4 short alligator clips and 4 connectors
  • Duct tape

The Arduino car chassis may require a small amount of assembly. Rather than soldering connections we like to use short alligator clips. It is not recommended to wire DC motors directly to a Raspberry Pi so the Pimoroni Explorer HAT Pro is used to connect the 2 DC motors.

The Raspberry Pi and the portable microUSB charger are secured to the top of the car chassis with duct tape. The left motor is wired to the motor 1 connectors on the Explorer Hat, and the right motor is wired to motor 2 connectors. Note you may have to do a little trial and error on the Explorer HAT “+” and “-” motor connections to get both wheels spinning in a forward direction.

The Explorer HAT Node-Red library is installed by:

 cd $HOME/.node-red
npm install node-red-dashboard 

The Web dashboard presentation is configured in the “dashboard” tab. For this example we create 2 groups: a control group to drive the vehicle, and a light group to turn on the Explorer Pro lights. Use the “+group” button to add a group, and the “edit” to change an existing group.
dash_conf

To control a motor, an “Explorer HAT” node and a dashboard button node are dropped and connected together. All the configuration is done in the button node . The button configure options are:

  • the group the button will appear in (Controls)
  • the size of the button (3×1 = 50% of width and narrow)
  • Topic, motor.one or motor.twois used for motor control
  • Payload, -100 = reverse, 0=stop, 100 = forward

Control_conf

The Explorer HAT has 4 colored LEDs. To toggle the LEDS, the topic is light.color with 1=ON, and 0=OFF . We thought that it would be fun to also add some Web dashboard button to control the colored lights.

light_conf

The Node-Red dashboard user interface is accessed by: ipaddress:1880/UI, so for example 192.168.1.102:1880/ui. Below is a picture that shows the final vehicle logic and the Web dashboard.

 

final_logic2

 

 

 

littleBits/Pi Temperature Monitor

By using littleBits Proto modules it is possible to create Raspberry Pi projects with littleBits components. On this project we created a temperature monitor with a local indication and a remote Web page using Node-Red.

The parts used were:

  • 1 Raspberry Pi 3
  • 1 Explorer Hat (used for Analog Inputs)
  • 2 littleBits Proto bits
  • 1 littleBits Temperature bit
  • 1 littleBits Number bit
  • 1 littleBits Wire bit (optional, used for easier wiring)

The Wiring

To complete the littleBits circuit the first Proto bit was wired with 5V to the VCC and the data connectors. Pi GND was wired to the module’s GND. The second Proto bit had the data pin with to the Explorer HAT analog input 1.

tempcircuit

Node-Red Logic

On the Pi, the following Node-Red nodes were used:

  • Explorer Hat Node – reads the analog input
  • Function Node – only pass on analog input 1
  • Smooth Node – removes noise and jitter
  • Function Node – converts 0-5V to 0-100 C

temp_logic

The logic for the first function node, (to pass only analog input 1), was:

 if (msg.topic == "explorerhat/analog.1"){
return msg;
} 

We added a smooth node to remove noise in the analog input signal. The configuration that we used for the smooth node was:

temp_smooth

The logic for the second function, (to convert the voltage to a temperature), was:

msg.payload= (100/5)*msg.payload;
return msg;

Finally we used a Chart Dashboard node to show the results on a Web page. Our configuration for this was:

temp_gauge

To view the Web page use the URL of : http://the-pi-address:1880/ui

temp_pic_full

Remote Controlled Rocket Launcher

We’ve made a number of different versions of the mobile rocket launcher, and all of them have been fun. The version above is using the a PI 1 with a PiFace Digital module for the motor controls and a wireless keyboard for the controls.

The version shown below is using a PI 3, with an ExploreHAT Pro for the motor controls and a Python Web Server program for the controls. By using some simplified HTML tagging we were able to use an old PSP as a remote interface console.

launcher

Rocket Launcher Sample Code

We found the rocket launcher in a sale bin, but they call be purchased at: http://dreamcheeky.com/thunder-missile-launcher. The rocket launcher comes with it’s own Windows based program.

Below is some Python code that will control the rockets launchers turret and fire a missile. Based on this sample code you should be able to make some cool projects. A couple of notes from our testing:

  • you need to manually stop the turret motion once you start it. So you need to set your own wait time
  • you need 3-4 seconds between each missile firing. It might be a coincident but we damaged our first rocket launcher trying to issue fast firing commands.
 import usb
import sys
import time

device = usb.core.find(idVendor=0x2123, idProduct=0x1010)

# On Linux we need to detach usb HID first
try:
device.detach_kernel_driver(0)
# except Exception, e:
except Exception:

pass # already unregistered

device.set_configuration()

endpoint = device[0][(0,0)][0]

down = 1 # down
up = 2 # up
left = 4 # rotate left
right = 8 # rotate right
fire = 16 # fire
stop = 32 # stop

#device.ctrl_transfer(0x21, 0x09, 0x0200, 0, [signal])

while True:

print('r = right, l = left, u = up, d = down, f = fire ')
key = raw_input ('enter key:')
if (key == 'l'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, left, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'u'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, up, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'r'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, right, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'd'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, down, 0x00,0x00,0x00,0x00,0x00,0x00])
if (key == 'f'):
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, fire, 0x00,0x00,0x00,0x00,0x00,0x00])
time.sleep(4)
time.sleep(0.1)
device.ctrl_transfer(0x21, 0x09, 0, 0, [0x02, stop, 0x00,0x00,0x00,0x00,0x00,0x00]) 

 

 

 

Android Controlled Robot Arm

Create a mobile robot arm that you can control from an Android smart phone.

We found a used robot arm (OWI-535) on Kijiji, but you could buy a new one for $30-$60.  We then mounted it on an Arduino car chassis ($20) with some duct tape. Luckily the OW-535 robot arm has all its wiring exposed and it comes with a good wiring document.

Parts

For this project we used:

  • 1- OWI-535 robot arm
  • 1- Car chassis ($17)
  • 1- Four motor Arduino shield ($10)
  • 1- Two motor Arduino shield ($10)
  • 1- JY-MCU Bluetooth module ($7)
  • 1- Arduino Mega
  • Duct tape, jumpers and 4 alligator clips
  • 1- Small USB charger
  • 1- Small Box (to house all the components)

OLYMPUS DIGITAL CAMERA

Wiring

The biggest challenge is to control the 5 robot motors and 2 wheel motors. For this we used an Arduino Mega and 2 motors shields. Depending on the motor shields that you use you probably won’t be able stack the motor shields. We stacked one motor shield and we had the second motor shield floating.

robot-arm-circuit

Some of the key wiring connections were:

  • Mega Pin 44 -> Floating Motor Shield pin 4
  • Mega Pin 45 -> Floating Motor Shield pin 5
  • Mega Pin 46 ->Floating Motor Shield pin 6
  • Mega Pin 47 -> Floating Motor Shield pin 7
  • Mega Pin 5V -> Floating Motor Shield pin 5V and VIN
  • Mega Pin 19 RX1 -> Bluetooth module TX
  • Mega Pin 18 TX1 -> Bluetooth module RX

To power this project we found that a portable USB charger was enough. If however you find that a USB charger does not deliver enough power the OWI-535 robot arm has a built in power pack with exposed power connections.

The motor terminals on the car chassis are a little fragile, so rather than soldering wires we used alligator clips. We also duct taped the wires under the car chassis to keep them secure.

The Arduino wiring was pretty ugly so we stuffed all the loose components into a small box. The box was duct taped to the back of the robot arm, and 2 cuts were made to feed the wires through.

inside_box.png

Code

For the Arduino code you’ll need to add the appropriate motor libraries. For our motor shields  we used the Adafruit V1 motor shield (https://github.com/adafruit/Adafruit-Motor-Shield-library).

Because the first motor shield blocked the RX0/TX0 pins, we used RX1 and TX1 on pins 19 and 18. For the Bluetooth communications it meant the Serial1 was used in the Anduino code instead of Serial.

For our commands we used:

  • 0 = Hand open (motor 1 forward)
  • 1 = Hand closed (motor 1 backward)
  • 2 = Wrist down (motor 2 forward)
  • 3 = Wrist up (motor 2 backward)
  • 4 = Elbow down (motor 3 forward)
  • 5 = Elbow up (motor 3 backward)
  • 6 = Shoulder up (motor 4 forward)
  • 7 = Shoulder down (motor 4 backward)
  • g = Go forward (pins: 44/46=HIGH, 45/47=255)
  • s = Stop (pins: 44/46=HIGH, 45/47 =0)
  • r = Right turn (pins: 44/46=HIGH, 45=0, 47 =255)
  • l = Left turn (pins: 44/46=HIGH, 45=255, 47 =0)
  • b = Go backward (pins 44/46= LOW, pins 45/47 =255)
  • o = Light ON, (pin 50 = HIGH)
  • f = Light OFF, (pin 50 = LOW)

Our final Arduino code is:

//
// Bluetooth control of a mobile robot arm
//
#include 

char inByte;
// Define remapped pins for 'floating' motor shield
int E1 = 45; 
int M1 = 44; 
int E2 = 46; 
int M2 = 47; 
int LIGHTpin = 50;

// DC motor on M1
AF_DCMotor motor1(1); // hand
AF_DCMotor motor2(2); // wrist
AF_DCMotor motor3(3); // elbow
AF_DCMotor motor4(4); // shoulder


void setup() {
 pinMode(M1, OUTPUT); 
 pinMode(M2, OUTPUT);

pinMode( 19, INPUT_PULLUP ); // For better Bluetooth stability
 Serial1.begin(9600); 
 Serial1.println("Robot Commands");
 Serial1.println("Menu...");
 Serial1.println("Enter: 0-7 for robot arm, g/s/l/r/b for wheels ");
}

void loop() {
 
 if (Serial1.available() > 0) {

// read the incoming byte:
 inByte = Serial1.read();
 if (inByte == '0') { runmotor(motor1,FORWARD); }
 if (inByte == '1') { runmotor(motor1,BACKWARD); }
 if (inByte == '2') { runmotor(motor2,FORWARD); }
 if (inByte == '3') { runmotor(motor2,BACKWARD); }
 if (inByte == '4') { runmotor(motor3,FORWARD); }
 if (inByte == '5') { runmotor(motor3,BACKWARD); }
 if (inByte == '6') { runmotor(motor4,FORWARD); }
 if (inByte == '7') { runmotor(motor4,BACKWARD); }
 if (inByte == 'g') { runwheels(HIGH,HIGH,255,255); } 
 if (inByte == 's') { runwheels(HIGH,HIGH,0,0); } 
 if (inByte == 'r') { runwheels(HIGH,HIGH,0,255); } 
 if (inByte == 'l') { runwheels(HIGH,HIGH,255,0); } 
 if (inByte == 'b') { runwheels(LOW,LOW,255,255); } 
 if (inByte == 'o') { digitalWrite(LIGHTpin, HIGH); }
 if (inByte == 'f') { digitalWrite(LIGHTpin, LOW); } 
 }
}
//--------------------------------------------------
void runwheels (int M1dir,int M2dir,int E1speed, int E2speed) {
 // For control of wheels direction and speed
 digitalWrite(M1, M1dir); 
 digitalWrite(M2, M2dir); 
 analogWrite(E1, E1speed);
 analogWrite(E2, E2speed); 
}
//--------------------------------------------------
void runmotor(AF_DCMotor themotor, int direction) {
 // Robot Arm motor control
 themotor.setSpeed(250);
 themotor.run(direction);
 delay(250);
 themotor.run(RELEASE); 
}

Android App

MIT’s App Inventor is free and it’s a great way to quickly make Android apps: http://ai2.appinventor.mit.edu/.

For this app we used:

  • 1 TableArrangement
  • 1 Listpicker
  • 15 Buttons
  • 7 Labels
  • 1 BluetoothClient (non-visible)

app1.PNG

A TableArrangement component with 3 columns and 11 rows is used to position all of the buttons and labels. After a component is positioned into the table, select the component and then use the Properties window to change its text, color, or sizing. The Components window is used to rename the component.

In the Blocks screen, blocks are dragged from the left Blocks section to the main viewer section. The following key blocks were used:

  • when Screen1.Initialize. This is called when the app is opened and it will show a list of all the phone’s paired Bluetooth device. This list is generated by connecting the blocks: BluetoothClient1.AddressesAndNames to set ListPicker1.Elements
  • when ListPicker1.BeforePicking. This block is called after the JY-MCU Bluetooth module (typically HC-06) is selected. Inside this block ListPicker1.Selection is an input to the Call BluetoothClient1.Connect block.
  • when .Click. This block is called when a “command” button is clicked. This block will send the required Bluetooth text command, so for example “g” is sent to go forward, and “s” is sent to stop.

app3

The full AppInventor code is:

full_logic

Once all the logic is created, you can download the app (APK file) or use a QR quick code to put it on your phone.

app2qr

The final step is to power up your Arduino project. When you do this the JY-MCU Bluetooth module will start to blink. This is telling you the module is ready to pair with your phone. On your phone’s SETUP->BLUETOOTH SETTINGS scan for new devices and you should see the JY-MCU Bluetooth module (it’ll probably be called HC-06). The pairing code is: 1234.

Now you are ready to open your new Android app. A dialog will ask you which device to connect to. Select your HC-06 device.

select

For this point on you will be able to control the robot with your phone.

screenshot