Monthly Archives: September 2012

RaspberryPi: A web API for gphoto

I was recently inspired by my good friend Josh Gallagher to flex my geek credentials when he mentioned he’d acquired a Raspberry Pi.  I’d seen mention of it on Engadget but had been too busy to pay much attention to it.  I’d seen an article on SLR Lounge about someone fitting one of these cheap little devices into a camera grip to control the camera so I thought I’d have a go at that.  I’m more of a software guy though, so I thought I’d try to see whether I could control my camera from my Nexus 7.

As a former web developer, my immediate instinct was to create a thin web API over gphoto2.  I would then be able to create a UI with HTML which I could use from any device with a browser.  As well as learning to use the Raspberry Pi I would also use this opportunity to learn a bit about Python.

The technology stack I ended up using was:

  • Python
  • Bottle v0.10 – a Sinatra like web framework
  • gphoto2
  • jQuery
  • Raspberry Pi
  • Nikon D3s

Although it would have been easy to just slap Mono on the box and whip up a .NET based solution, I thought it would be more challenging to use something entirely unfamiliar.  I spent about two days looking through Learn Python the Hard Way to get myself up to speed.  Getting to grips with the basic language syntax was fairly straightforward and it was actually quite fun learning something new.

Before writing any kind of web based API, I wanted to prove the concept of hooking up my camera and getting the RPi talking to it.  So this is where I hit the first problem that was mentioned in David Hunt’s post, which regards the limitations of the RPi’s USB controller.  The limitation manifests itself with having to disconnect and then reconnect the camera because of what appear to be random PTP I/O errors.  David mentions the use of a C script to reset the USB port.  A lot of googling later I eventually found the C script in question.  More googling and we have a bash script to string together the requisite commands that will control the camera:

dev=`gphoto2 --auto-detect | grep usb | cut -b 36-42 | sed 's/,///'`
if [ -z ${dev} ]
 echo "Error: Camera not found"
resetusb /dev/bus/usb/${dev}
gphoto2 $@
resetusb /dev/bus/usb/${dev}

Deciding on a suitable web framework took a bit of time. After several failed attempts to get Django to work with Apache, I went with Bottle as a lightweight web framework and ditched both Django and Apache.

Getting python to call out to a bash script felt a bit clunky though and turning that part into a python script was fairly straight forward.  Python has the subprocess module which allows python to call out to other “executables” on the system and return data back to the python script.  This results in a couple of simple python methods that can be combined to call out to gphoto and return the appropriate result:

def resetusb():
    if global_usb_port != None:
        subprocess.Popen(['sudo', '/home/pi/usbreset', '/dev/bus/usb/' + global_usb_port])
        return True
        return False

def detectcamera():
    gphoto_detect = subprocess.check_output(['sudo', 'gphoto2', '--auto-detect'])

    if gphoto_detect == None:
        return False

    usb_device = gphoto_detect.split(":")

    if len(usb_device) < 2:
        return False
        usb_device = usb_device[1].strip().replace(",","/")

    global global_usb_port
    global_usb_port = usb_device
    return True

def execute(command):
    if detectcamera() == False:
        return "Camera not found"

    gphotocommand = ['sudo', 'gphoto2'] + command
    gphoto_response = subprocess.check_output(gphotocommand)

    return gphoto_response

Using Bottle to create the web API also proved to be straightforward.  The one problem I encountered was getting gphoto to capture the image and display it on the web page.  Turns out that the image downloaded is saved as read-only and overwriting it with python caused a prompt.  As it’s a web process, I didn’t get the prompt until I tried to replicate the issue from the command line.  The solution was to copy the file to the location where Bottle was set up to serve static files and then delete the original file.

With what I’ve done so far I can (for any camera supported by gphoto2):

  • List all the configuration options that the camera presents
  • View individual configuration options
  • List the camera’s abilities
  • Capture an image and display it on the webpage

Things to do:

  • Ability to change configuration values
  • Ability to string together a series of commands – this should allow things like bracketing and time lapse photography (although the D3s already has a bracketing function)
  • Sort out the hardware side of things so I can attach the RPi to the camera and operate it in the field from my Nexus 7
  • Use a data store to store camera specific settings and preferences
  • Put the source code up on github. Source code can be found on github