Python For Maemo 5 Info

The python used in the Nokia N900 is known as PyMaemo. It is basically the normal python, with additional device related commands.

API Documentation (non-pythonic): Maemo 5 Api Docs

Python Tutorials: Python for newbies

It is also possible to access C APIs that don't have Python bindings. However, this can bring some interesting problems. Not recommended, as most of the maemo APIs should work just fine with Python. However, check Accessing APIs without Python bindings for more info.

Playing Sounds

N900 can play sounds with two different ways - Either using gstreamer or pygame. This example is made with pygame as it provides a higher-level API and requires less magic words ;-) Pygame documentation can be found behind the following link: PyGame Documentation

The sound file used in this example: Sound file

Here is a proper Object-Oriented implementation of a Player that can load and play sound files. I suggest creating a list of sound objects that are loaded with this player and then playing those when needed (faster than opening a file for playback each time separately).

soundplayer.py
"""
August 9, 2011
 
@author: Janne Parkkila
@email: japskua@gmail.com
 
@summmary: This file contains code for playing music/sounds on N900
           with Python programming language. This implementation uses
           pygame instead of gstreamer
"""
 
import pygame
 
class Player(object):
 
    def __init__(self):
        """
        @summary: The Constructor class
        """
        pygame.mixer.quit()
        pygame.mixer.init()
        pygame.init()
 
    def Play(self, sound):
        """
        @summary: This function is used to play the given sound
        @param sound: The sound to be played
        @type sound: pygame sound object 
        """
        sound.play()
 
    def Load(self, filename):
        """
        @summary: This function loads the given filename into a pygame
                  readable sound object
        @param filename: The path to the file to be loaded
        @type filename: String
        @return: Loaded pygame music object
        @rtype: pygame Sound
        """
 
        return pygame.mixer.Sound(filename)
 
if __name__ == "__main__":
    # Initialize the player
    player = Player()
    # Load the soundfile with the player
    sound = player.Load("button-4.wav")
    # Play the file
    player.Play(sound)

However, if you want to make something better yourself, here is the basic simple version of the same thing

simple-sounds.py
import pygame
 
pygame.mixer.init()
pygame.init()
 
sound = pygame.mixer.Sound("button-4.wav")
sound.play()

Using Microphone

This code snippet uses gstreamer to record voice through the phone microphone. Notice that there is a small lag on starting the recording and after stopping the record. This is purely related to gstreamer and should be taken into account when developing applications. So, don't wait zero response time with this code :-P

Note: If this doesn't work, you are probably missing some gstreamer related plugins Get them with:

sudo gainroot
apt-get install gstreamer0.10-alsa gstreamer0.10-flac gstreamer0.10-plugins-good-extra
microphone.py
#!/usr/bin/env python
 
# This is the MIT license:
# http://www.opensource.org/licenses/mit-license.php
 
# Copyright (c) 2009 Digital Achievement Incorporated and contributors.
 
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
 
"""
@summary: This file contains the data for SoundRecorder on Nokia N900 using Python and gstreamer.
          The code is based on the source by Digital Achievement and is available from:
          http://achievewith.us/public/articles/2009/01/28/using-gstreamer-and-python-to-record-audio
@author: Janne Parkkila (the modified Object Oriented Version)
@email: japskua@gmail.com
 
@requires: gstreamer0.10-alsa, gstreamer0.10-flac, gstreamer0.10-plugins-good-extra
"""
 
from optparse import OptionParser
 
import dbus
import gst
import sys
import time
 
class SoundRecorder(object):
    """
    @summary: This is the SoundRecorder class that handles locating the microphone
              and capturing voice from the mic. Currently uses somewhat "dirty" method of
              calling gstreamer via command line, but works pretty well nonetheless :-D
    """
 
    mic = None
 
    def __init__(self):
        """
        @summary: The Constructor class, that searches for the microphone on initialization
        """
        bus = dbus.SystemBus()
        hal_manager = bus.get_object("org.freedesktop.Hal",
                                     "/org/freedesktop/Hal/Manager")
        hal_manager = dbus.Interface(hal_manager, "org.freedesktop.Hal.Manager")
 
        print hal_manager
        devices = hal_manager.FindDeviceStringMatch("alsa.type", "capture")
 
        identifiers = []
 
        for dev in devices:
            device = bus.get_object("org.freedesktop.Hal", dev)
 
            card = device.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device")
            if card["alsa.card"] not in identifiers:
                print "%d. %s" % (card["alsa.card"], card["alsa.card_id"])
                identifiers.append(card["alsa.card"])
 
        self.mic = identifiers[0]
 
 
    def Record(self, destination):
        """
        @summary: Records the audio with the microphone and saves to the given destination
        @param destination: The destination where to save the captured voice
        @type destination: String
        """
 
        pipeline = gst.parse_launch("""alsasrc device=hw:%d ! audioconvert ! level name=recordlevel interval=10000000 ! audioconvert ! flacenc ! filesink location=%s""" % (self.mic, destination))
        pipeline.set_state(gst.STATE_PLAYING)
 
        print "recording, press enter to stop"
        sys.stdin.readline()
 
        pipeline.set_state(gst.STATE_NULL)
        time.sleep(5)
 
if __name__ == "__main__":
    # This is used if the code is run straight from the command line
    recorder = SoundRecorder()
    recorder.Record("output.wav")

Using Camera

This code uses the N900's camera to take picture. It is not very sophisticated, as the back camera does not use flash (at least with the current implementation). Also, not that the Python does not really support taking pictures, thus requiring user to take pics by calling gstreamer through command line. This is an evil hack and will steal your soul. You can only use this as a super user Which gives me SUPER POWERS!! MUAHAHHAAHAHAA!!!

so please, before running any camera python apps (at least based on my code) make sure you do

sudo gainroot
python camera.py
 
(or in scratchbox)
 
fakeroot
python2.5 camera.py
camera.py
"""
August 9, 2011
 
@author: Janne Parkkila
@email: japskua@gmail.com
 
@summary: This file contains code for taking pictures with the front or the back
          camera of the nokia N900. The file provides python access to the camera
          but really just uses command line to take picture.
 
@note: PyMaemo has no possiblity to capture pictures, thus this gstreamer capture is used
       via command line. This requires super user rights, so if you are using this file
       you can only take pictures with as a sudoer.
 
       ALSO! MAKE SURE THE CAMERA LID IS OPEN WHEN TAKING THE PICTURE!!! :-P
"""
import sys
import gst
import os
 
 
class Camera(object):
    """
    @summmary: This is the camera object that is capable of capturing pictures
               with either the front or the back camera of the device
    """
    back = None
    front = None
 
    def __init__(self):
        """
        @summary: The Constructor
        """
        self.back = "gst-launch v4l2src device=/dev/video0 num-buffers=1 ! ffmpegcolorspace ! jpegenc ! filesink location="
        self.front = "gst-launch v4l2src device=/dev/video1 num-buffers=1 ! ffmpegcolorspace ! jpegenc ! filesink location="
 
    def TakePicture(self, camera, filename):
        """
        @summary: The function for taking pictures with the camera
        @param camera: The camera to be taken pictures with
        @type camera: String, either "FRONT" or "BACK"
        @param filename: The path to the file where to save the taken picture,
                         without the filetype suffix.
        @type filename: String
        """
        photo = None
 
        if camera == "FRONT":
            photo = self.front + filename + ".jpg"
        elif camera == "BACK":
            photo = self.back + filename + ".jpg"
        else:
            print "Error, camera should be either FRONT or BACK"
 
        os.system(photo)
 
 
 
# If this program is executed as itself
if __name__ == "__main__":
    camera = Camera()
    camera.TakePicture("FRONT", "frontcam")
    camera.TakePicture("BACK", "backcam")

Bluetooth

Bluetooth stuff here

Using Accelerometer

Download this source from here: Accelerometer.py

accelerometer.py
"""
Created August 9, 2011
 
@author: Janne Parkkila
@contact: japskua@gmail.com
 
@summary: This file contains class implementation on connecting 
          to maemo dbus and receiving accelerometer data
"""
 
import dbus
 
class Accelerometer(object):
    """
    @summary: This class is used to get accelerometer data
              from the dbus
    """
 
    bus = None
    accelerometer = None
 
    def __init__(self):
        """
        @summary: The Constructor for the class
        """
        self.bus = dbus.SystemBus()
        self.accelerometer = self.bus.get_object("com.nokia.mce",
                                            "/com/nokia/mce/request",
                                            "com.nokia.mce.request")
 
    def getData(self):
        """
        @summary: This function returns the data of the accelerometer
        @return: orientation, stand, face, x, y, z
        @rtype: list
        """
        return self.accelerometer.get_device_orientation()
 
 
    def displayData(self):
        """
        @summary: This function is just used to display data
        """
        orientation, stand, face, x, y, z = self.getData()
        print "Orientation: ", orientation
        print "Stand: ", stand
        print "Face: ", face
        print "X: ", x
        print "Y: ", y
        print "Z: ", z
 
 
# This is only if we want to run the accelerometer test straight from the command line
if __name__ == "__main__":
    print "Starting the Accelerometer test"
    accel = Accelerometer()
    accel.displayData()

Using Location API

Note: The python location might not be installed on the device. In this case, you need to install it with apt-get install python-location

IMPORTANT TO NOTICE The GPS on the N900 is not very fast! Acquiring a signal can take a great amount of time. Thus it is just recommended to simulate this in some other manner. The probability of receiving a signal in the basement is really small, so please, don't waste too much of your precious time with this.

More info on location API with pyMaemo can be found from:

The following file is brutally ripped from the Maemo wiki:

gps.py
import location
import gobject
 
def on_error(control, error, data):
    print "location error: %d... quitting" % error
    data.quit()
 
def on_changed(device, data):
    if not device:
        return
    if device.fix:
        if device.fix[1] & location.GPS_DEVICE_LATLONG_SET:
            print "lat = %f, long = %f" % device.fix[4:6]
            # data.stop() commented out to allow continuous loop for a reliable fix - press ctrl c to break the loop, or program your own way of exiting)
 
def on_stop(control, data):
    print "quitting"
    data.quit()
 
def start_location(data):
    data.start()
    return False
 
loop = gobject.MainLoop()
control = location.GPSDControl.get_default()
device = location.GPSDevice()
control.set_properties(preferred_method=location.METHOD_USER_SELECTED,
                       preferred_interval=location.INTERVAL_DEFAULT)
 
control.connect("error-verbose", on_error, loop)
device.connect("changed", on_changed, control)
control.connect("gpsd-stopped", on_stop, loop)
 
gobject.idle_add(start_location, control)
 
loop.run()