download by janobyl3


									        Tutorial: Python For S60

                     Agathe Battestini
                Nokia Research Center - Palo Alto

Dec 2nd, 2008 
• Introduction: phones, download, installation,
• PyS60 phone modules
• Extensions, Security platform
• PythonForS60 for middleware development

Videos of all the test scripts:

  Dec 2nd, 2008
                      Python For S60
  • Available for Symbian S60 phones
3rd Ed            3250, 5500 Sport, E50, E60, E61, E62, E65, E70, N71, N73,
                  N75, N77, N80, N91, N91 8GB, N92, N93
3rd Ed FP1        5700 XpressMusic, 6110 Navigator, 6120 Classic, 6121
                  Classic, 6124 Classic, 6290, E51, E66, E71, E90
                  Communicator, N76, N81, N81 8GB, N82, N95, N95 8GB
3rd Ed FP2        5320 XpressMusic, 6210 Navigator, 6220 Classic, 6650, N78,
                  N79, N85, N96
2nd Ed FP1        6600, 3230, 6260, 6620, 6670, 7610
2nd Ed FP2        6630, 6680, 6681, 6682
2nd Ed FP3        N70, N72, N90

  Dec 2nd, 2008     


Dec 2nd, 2008
• Open Source
• Is based on Python interpreter 2.2.2
• Latest version of PythonS60: 1.4.4
  (June 2008)
• Release 2-3 times a year or more

Dec 2nd, 2008
        Installation on the phone
• Install the Python S60 interpreter .sis
      QuickTimeª see this picture.
    are needed toand a
     TIFF (LZW) decompressor


• Install the Python Shell.sis
    are needed toand a
      QuickTimeª see this picture.
     TIFF (LZW) decompressor                               The shell sis has
                                                       to be signed e.g to access
                                                       location/positioning modules

Dec 2nd, 2008         
                Windows Emulator
• Download S60 Platform SDKs for

   or Nokia Forum → Tools and SDK → Symbian/C++ tools

• Download SDK Python For S60

• You can run Python scripts in the

Dec 2nd, 2008   
      Firefox emulator + lighttpd
• Improve development cycles
  by being able to run a PyS60
  code on the destop
• Similar to PDIS compatibility
  library     QuickTimeª and a
                                                TIFF (LZW) decompressor
                                              are needed to see this picture.

• Works with SCGI server and
• The PyS60 runs in the

Dec 2nd, 2008
                ... PyS60 modules...

Dec 2nd, 2008
import location
cell_info = location.gsm_location()
if 4==len(cell_info):
   mcc,mnc,lac,cid = cell_info

import location, e32
cell_info = location.gsm_location()
while 1:
   if 4==len(cell_info):
       mcc,mnc,lac,cid = cell_info                     Need location
   e32.sleep(60*2)                                     capability

Exercise: write function to get location, display the country
(from the list of MCCs), and in menu: items start / stop
    Dec 2nd, 2008
import positioning
requestor = {'type':'service', 'format':'application',
pos = positioning.position(course=1, satellites=1)
if pos and pos.has_key('position'):
   lat = pos['position']['latitude']
   lon = pos['position']['longitude']
   print "GPS:", lat, lon

                                                       Need location

Exercise: poll positioning every x seconds, write into a file
    Dec 2nd, 2008
                    inbox (to read SMS)
import inbox
received_box = inbox.Inbox(inbox.EInbox)
sent_box      = inbox.Inbox(inbox.ESent)
msg_ids       = received_box.sms_messages()
msg_ids.sort()       # ascending order
id = msg_ids[0]      # get the first one (the oldest SMS)
sms = {'content' : received_box.content(id),
        'date'    : received_box.time(id),
        'address' : received_box.address(id),
        'status' : received_box.unread(id),
        'id'      : id, }
print "The oldest SMS I received: ", sms

Exercise: Backup messages in a file ; bag of words (per
person, in total) ; display all messages by one person ; search
in messages
    Dec 2nd, 2008
          inbox (new SMS callback)
import inbox
received_box = inbox.Inbox(inbox.EInbox)
def callback(new_id):
   sms = {'content' : received_box.content(new_id),
        'date'    : received_box.time(new_id),
        'address' : received_box.address(new_id),
        'status' : received_box.unread(new_id),
        'id'      : new_id, }
   print "You got a message!"

Exercise: answer automatically an SMS if it comes from
specific contacts and contains specific words

    Dec 2nd, 2008
          messaging (to send SMS)
 import messaging
 contact_number = "+16501112222"
 contact_name   = "John"
 gps            = (50.87780, 4.70382)
 message        = u("Hey, I'm in Belgium. Exactely here:
 messaging.sms_send(contact_number, message, name=contact_name)
 print "Message was sent"

Exercise: send SMS with callback, send MMS with attached
    Dec 2nd, 2008
                 contacts (phonebook)
 import contacts
 # Backup all contacts as vcards, in a text file
 cdb =
 ids = cdb.keys()
 f   = open('./contacts_backup.txt', 'w+')
 for id in ids:
    vcard = cdb.export_vcards( [id,])
    info = { 'vcard'        : vcard,
             'date.modif'   : cdb[id].last_modified,
             'id'           : id, }

Exercise: read backup file, read vcards with vobject package; clean up contacts
     Dec 2nd, 2008
 import calendar, time
 cdb = calendar.CalendarDb()
 print "There are %s calendar entries "%len(cdb)
 # Get all entries until now + one month

 one_week_in_seconds = 60*60*24*7
 entries = cdb.find_instances(time.time()-one_week_in_seconds,
 one_id = entries[0]
 one     = cdb[one_id['id']]
 print "one_id, one

 for el in ['type' ,'alarm', 'id', 'content', 'end_time', 'last_modified',
    'location', 'originating', 'priority', 'replication', 'start_time',]:
    print "%s: "%el, one.__getattribute__(el)
 vcal = cdb.export_vcalendars((one_id['id'], ))
Exercise: read vcal with vobject package;
     Dec 2nd, 2008
                  appuifw (popup things)
 import appuifw

 for typ in ['text', 'code', 'number', 'float', 'date', 'time', 'query',]:
     res = appuifw.query(u"Give me a %s"%typ, typ)
     print res

 options = map ( lambda x : u'Option %s'%x, range(0,5))
 res = appuifw.popup_menu(options, u"Which option do you want?")
 appuifw.note(u"You have selected %s (%s) "%(options[res], res), 'info')

 res = appuifw.selection_list(options, search_field=0)
 print res

 res = appuifw.multi_query(u"This", u"That")

 options = map ( lambda x : u'Option %s'%x, range(0,100))
 res = appuifw.multi_selection_list(options, style='checkbox', search_field=1)
 print res
 appuifw.note(u"Uh uh this does not work: %s (%s) "%(options[res[0]], res[0]), 'error')

Exercise: randomly ask what the user is doing and log

      Dec 2nd, 2008      
                         appuifw (app)
 import appuifw

 t = appuifw.Text()
 t.add(u"You can display things here, or let the user write: \n") = t
 full_s = t.get()
 print t.font
 print appuifw.available_fonts() = u"Py app" = 'full'          # 'normal' , 'large', 'full'

 def do_something(s='?'): t.add(u" %s \n\n"%s)[ (u"Print 1" , lambda: do_something(1) ),
                     (u"Print ?" , do_something           ),
                     (u"Do nothing", lambda: None         ), ]

Exercise: app that shows a random selection of pictures, SMS

      Dec 2nd, 2008    
                     appuifw (a template)
import appuifw, e32
class MyApp:
    def __init__(self):
          self.lock = e32.Ao_lock()
 = u"My App"
          # create UI elements
 = appuifw.Listbox( [u"Item 1", u"Item 2"], self.lb_callback)
    def activate(self):
[ (u"Help", lambda: None), (u"Exit", self.key_exit), ]
 = self.key_exit
    def key_exit(self):
    def lb_callback(self):
          i =
          appuifw.note(u"List callback selection: %s"%i, 'info')
    def run(self):

if __name__=="__main__":
    global myapp
    myapp = MyApp()
     Dec 2nd, 2008      
                        appuifw (Listbox)
import appuifw

# List with a single line
def callback():
    current_i = lb.current()
    appuifw.note(u"'%s' (%s) was selected"%(l[current_i], current_i), 'info')

l = [ u"Thing %s"%i for i in range(0, 10) ]
lb = appuifw.Listbox(l, callback) = lb

# List with double line
l = [ (u"Thing %s"%i, u"with more info about thing %s"%i) for i in range(0, 10) ]
lb = appuifw.Listbox(l, callback) = lb

     Dec 2nd, 2008      
    key_codes (binding key events)
import key_codes, appuifw

# You can delete things off the list
def delete_callback():
    current_i = lb.current()
    if len(l)==0:
          l.append(u"Nothing") # you cannot have an empty list
    if len(l)>current_i-1 and current_i-1>=0:
          lb.set_list(l, current_i-1)

l = [ u"Thing %s"%i for i in range(0, 10) ]
lb = appuifw.Listbox(l, callback)
lb.bind(key_codes.EStdKeyHome, delete_callback) # it's the 'C - delete' key = lb

     Dec 2nd, 2008      
        (capturing global key events)
import keycapture, appuifw, e32, key_codes

# create a dict of the integer code values, and the name of the key code
values_keynames = dict( [ [val, key] for key, val in key_codes.__dict__.items() if

t = appuifw.Text(u"Press a key\n") = t

def callback(key):
    t.add(u"\nKey pressed: keycodes.%s (%s)"%(values_keynames[key], key))

capturer = keycapture.KeyCapturer(callback)
capturer.keys = keycapture.all_keys
capturer.forwarding = 0


     Dec 2nd, 2008         
 import appuifw

 # draw once
 c = appuifw.Canvas() = c
 c.line([0,0, 200, 250], outline=0x00ff00)

 # redrawn after the application screen was hidden by something
 def redraw(area_coords):
    c.rectangle([0,0, c.size[0], c.size[1]], fill=0x88eeee)
    c.line([0,0, 200, 250], outline=0x00ff00, width=3)

 c = appuifw.Canvas(redraw) = c

Exercise: use the other functions - ellipse, arc, polygon, point,
text, clear
      Dec 2nd, 2008 
                      Canvas and graphics
 import appuifw, graphics

 c = appuifw.Canvas() = c

 # draw on a buffer
 buf =
 im ="C:\\Data\\myapp\\miata.png")
 buf.line([0,0, im.size[0],im.size[1]], outline=0xff0000, width=10)
 buf.line([0,im.size[1],im.size[0], 0], outline=0xff0000, width=10)
 buf.text([100, 220], u"SOLD", font=(appuifw.available_fonts()[0],

Exercise: add a redraw callback ; take a screenshot

      Dec 2nd, 2008 
 import appuifw

 # Create a simple html file
 open("C:/Data/myapp/waffles.html", "w+").write(
 <html> <body><h1>Best Waffles are in Belgium</h1><img
    src='' />

 ch = appuifw.Content_handler()
 # This opens the default web browser because it's a .html file"C:\\Data\\myapp\\waffles.html")

Exercise: pass a callback to Content_handler; use the
open_standalone function; download favorite URLs for offline
     Dec 2nd, 2008
                        camera (pictures)
 import camera, appuifw

 # Take a photo and display it = appuifw.Canvas()
 image = camera.take_photo()

 # Use the viewfinder
 def callback(image):



Exercise: bind a key event to a function that takes the photo
and saves it in a file
      Dec 2nd, 2008    
                      camera (videos)
 import camera, appuifw, e32 = appuifw.Canvas()

 def callback(image):


 def video_cb(code, status):
    print code, status

 fn = "C:\\Data\\myapp\\video01.mp4"
 e32.ao_sleep(10) # make a 10 seconds video

Exercise: upload the video

      Dec 2nd, 2008    
 import telephone, e32

 e32.ao_sleep(20) # gives some time to the other person
   to answer

Exercise: Implement the SOS phone call - 2 features:
- The application listens for incoming SMS, if a new SMS includes
'SOS call me', a call is made to the corresponding number
- Click 'send SOS', an SMS is sent to your emergency contact
with 'SOS call me'
     Dec 2nd, 2008
 import audio, e32

 # Play an mp3 file
 fn = u"C:\\Data\\myapp\\secosmic_lo.mp3"
 sound =
 e32.ao_sleep(sound.duration()/1000000 + 3) # convert in s + 3s

 # text to speech
 audio.say(u"Hello! How are you?")

     Dec 2nd, 2008
 import audio, e32, os, random, time


 dir = u"C:\\Data\\myapp\\wavs\\"
 list_wavs=[f for f in os.listdir(dir) if f[-4:]==".wav"]
 sounds = [ for fn in list_wavs]

 for i in range(0, 30):
    r_i = int(random.random() * len(sounds))
    if sounds[r_i].state() != audio.EOpen:

 for s in sounds: s.close()

Exercise: record the music at the same time ; use the
accelerometer as input
      Dec 2nd, 2008 
 import e32, appuifw
 e32.ao_sleep(2) # in seconds. time.sleep(2) would make the UI freeze too

 inactivity_in_seconds = e32.inactivity()

 # copy a file: (target, source), and only \\ as separator
 e32.file_copy('E:\\'+random_script, 'C:\\Python\\'+random_script)

 # let the user select a drive
 i = appuifw.popup_menu(e32.drive_list(), u"Select where to put the secret files")
 appuifw.note(u"You have selected %s"% e32.drive_list()[i], 'info')

 # Other functions are available
 for f in dir(e32):
    print f


      Dec 2nd, 2008 
simple serialization (conf, data files)
 import os, os.path

 FILE_PATH = "C:/Data/myapp"
 user_conf = {} # empty or with default values

 def open_config_file():
     conf_f = os.path.join(FILE_PATH, "user.conf")
     if os.path.exists(conf_f):
           s = open(conf_f, 'r').read()
           if len(s)>0:

 def write_config_file():
     conf_f = os.path.join(FILE_PATH, "user.conf")
     open(conf_f, 'w+').write(repr(user_conf))

 if __name__=="__main__":
     user_conf['login'] = ''


      Dec 2nd, 2008      
               sensor (log sensor data)
 import sensor, appuifw, e32
 FILENAME = "C:/Data/myapp/sensor_data.txt"
 global data, gesture, sensor
 def callback_acc(val):
     data.append( [val['data_1'], val['data_2'], val['data_3'] ])

 def stop_acc():
     f = open(FILENAME, "ab+")
     f.write(repr( {'gesture' : gesture, 'data': data } ))
     f.write("\n") ; f.close()

 def get_gesture_data():
     global data, gesture
     data = []
     gesture = appuifw.query(u"Information about the recorded data", 'text')
     e32.ao_sleep(2) # get data for 2s

 acc_info = sensor.sensors()['AccSensor']
 sensor = sensor.Sensor(acc_info['id'], acc_info['category'])

Exercise: process the data to correlate gesture and accelerometer
      Dec 2nd, 2008      
 import logs

 # easy access to the phone logs
 for typ in ['call', 'sms', 'data', 'fax', 'email', 'scheduler']:
    data = logs.log_data(typ)
    print "\n%s logs: "%typ
    if len(data)>0:
         print len(data), data[0]
         print 0


     Dec 2nd, 2008
                      -standard Python module-
 import urllib, appuifw

 f = urllib.urlopen("")
 html =

 # post GET data to an online image collection
 keyword = appuifw.query(u"Keyword for the image search:", 'text')
 keyword = keyword and keyword or 'ship'
 params = urllib.urlencode({'f' : 'search', 'txt' : '%s'%keyword, 'w':'1', 'x' :
    '0', 'y' : '0'})
 f = urllib.urlopen(""+params)
 html =
 print "Length of the HTML file ", len(html)

Exercise: Save the html locally, open it in the browser (using
Content_handler) ; Parse the html
      Dec 2nd, 2008 
                 ftplib (upload the video)
                      -standard Python module-
 import ftplib

 fn = "C:\\Data\\myapp\\video01.mp4"
 f = open(fn, 'rb')

 host = ""
 user = "pymobmid"
 pwd = "pymid"

 ftp = ftplib.FTP(host)
 ftp.login(user, pwd)
 ftp.storbinary("STOR video01.mp4", f, 1024)
                                                       ftplib is not installed by
                                                       default. Copy
                                                       to the phone.

Exercise: upload the video

      Dec 2nd, 2008 
                      socket (Bluetooth)
 import socket, appuifw

 # Send a file to a Bluetooth device
 selected_bt = socket.bt_obex_discover()
 fn = u"C:\\Data\\contacts_backup.txt"
 socket.bt_obex_send_file(selected_bt[0], selected_bt[1].values()[0], fn)

 # List of Bluetooth devices
 list_bt = socket.bt_discover()

Exercise: Create a BT server
For better BT support, see
      Dec 2nd, 2008 
                               socket (inet)
                      -modified standard Python-
 import socket
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.bind( ("", 18000) )
 conn, addr = s.accept()
 while 1:
     data =
     if not data: break
     question = eval(data)
     conn.send( repr({'result': eval(question['exp'])}))
 # Start server with: e32.start_server(u"C:\\Data\\myapp\\")

 import socket
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.connect(("", 18000))
 s.send( repr({'exp': '10*80'}))
 data =
 print "Result", eval(data)

Exercise: make the server more robust, handle more commands
      Dec 2nd, 2008      
              sysinfo (phone params)
 import sysinfo
 info = {'imei'                  :   sysinfo.imei(),
         'battery.level'         :   sysinfo.battery(),
         'active.profile'        :   sysinfo.active_profile(),
         'ring.type'             :   sysinfo.ring_type(),
         'signal'                :   sysinfo.signal_dbm(),
         'signal.bars'           :   sysinfo.signal_bars(),
         ''             :   sysinfo.total_ram(),
         ''              :   sysinfo.free_ram(),
         # 'ram.max'             :   sysinfo.max_ramdrive_size(),
         'rom'                   :   sysinfo.total_rom(),
         ''            :   sysinfo.free_drivespace(),
         'display.pixels'        :   sysinfo.display_pixels(),
         'display.twips'         :   sysinfo.display_twips(),
         'sw.version'            :   sysinfo.sw_version(),
Exercise: log battery level and activity

     Dec 2nd, 2008
                          _ _builtins_ _
                      -standard Python module-
 # get the list of the methods (for objects), or functions available in modules
 print dir(__builtins__)
 print dir(''), dir([]), dir({})

 # call a script:
 import os
 random_script = os.listdir('C:/Python')[2]
 print "We are calling ", random_script

 # local variables are stored in a dict returned by locals()
 print locals()
 city     = 'Leuven'
 country = 'belgium'
 print "I am in %(city)s, in %(country)s"%({'city' : city, 'country': country})
 # or simpler:
 print "I am in %(city)s, in %(country)s"%locals()

Exercise: map, filter, lambda, globals, unicode, hex, chr, int, ...

      Dec 2nd, 2008 
          ... modules presented here
 e32                 #   symbian OS functions/class
 sysinfo             #   system info
 appuifw             #   GUI framework
 graphics            #   images, drawing
 camera              #   to take photos or videos
 sensor              #   access to the phone sensors
 audio               #   play mp3, wav, record audio
 telephone           #   dial, hang up
 messaging           #   send, receive SMS
 inbox               #   access to the messaging inbox, sent boxes
 location            #   cellid location
 positioning         #   GPS location
 contacts            #   access to the phone book
 logs                #   access to the phone's logs
 keycapture          #   capture global key events
 calendar            #   access to the calendar


     Dec 2nd, 2008     
    ... modules not presented here

 globalui           #   notifiers for global events
 topwindow          #   to show windows on top of the others
 gles, glcanvas     #   open GL bindings
 e32db, e32dbm      #   interface to the symbian native database


    Dec 2nd, 2008
                ... About PyS60...

Dec 2nd, 2008
         Availability of standard Python
               modules in PyS60
                                                                       PY : Python module
                                                                       PYD: DLL (C/C++)module
                                                                       built-in: C/C++ module

                                                                        X : included in PyS60

                                                                       (X): not included but
                                            QuickTimeª and a
                                        TIFF (LZW) decompressor
                                                                          works both on phone
          QuickTimeª and a
      TIFF (LZW) decompressor
                                     are needed to see this picture.      and SDK
   are needed to see this picture.


        Dec 2nd, 2008          
                How to extend PyS60
1. Try to import / run the Python files on the phone
    •   Use files from Python 2.2.2 / 2.2.3 distribution
•   Create a PyS60 extension (Symbian DLL .pyd)
    •   Sometime existing extensions do that for you
    •   Otherwise, it requires installing the Symbian SDK +
        PyS60 SDK and writing Symbian C++ or OpenC code

    Dec 2nd, 2008
               Advantages of PyS60
• All advantages of Python
   – Good support for client-server communications
   – Dynamic programming, etc
• Connectivity: WIFI, GPRS/3G, Bluetooth
• Stable, access to a lot of the phone features
• A good choice for prototyping
   – And products:

• If you do not need advanced GUIs or a look&feel different
  from basic S60: PyS60 is an excellent choice

   Dec 2nd, 2008
     Alternatives (Nokia products)
• Nokia widgets:

   – Javascript APIs to access the phone resources: location, calendar,
     contacts, logging, media, messaging, system info
• Linux tablets: N800, N810
   – Normal Debian Linux distribution
• Qt for S60:
   – Currently preview release
• S60 Open C

   Dec 2nd, 2008    
   Symbian Security platform                            TIFF QuickTimeªsee
                                                         are (Uncompresse
                                                              needed to

• To install an application on the phone, the application needs
   to be signed with a certificate that itself defines what
   capabilities it can grant.
• Applications/extensions specify what capabilities need to be
   granted for them to function.

The best strategy for academic groups:
• Request an R&D certificate with ALL capabilities except DRM
   and TCB.
• Register the phone IMEIs with the certificate (online)

   Dec 2nd, 2008

To top