PyS60 is a port of Python 2.2 for Series 60 ("S60") smartphones. Such cell phones are big, powerful, have almost as much hardware as a notebook, are as fast as a 1998 IBM PC, and now they run Python.
The S60 platform is based on Symbian operating system. Symbian is developed by the Symbian Ltd. consortium, of which the major cellphone makers have a share: Nokia, Motorola, Siemens, Sony-Ericsson etc. Symbian is not complete by itself; some features as the UI are built on top of it, so there are several platform "flavors" running on top of Symbian, analog to the several Linux distributions that use KDE or GNOME or WindowMaker.
Series 60 is one of those "flavors", probably the most proeminent of them. Most of S60 phones are Nokia, but there are exceptions. Take a look at http://www.s60.com to see all S60 phones from different manufacturers.
Other Symbian-based platforms are Series 80 and Series 90 from Nokia. Those series seem to be dead-ends since Series 60 has now sufficient power to handle bigger screens and complete keyboards. Another Symbian platform is UIQ, found in non-Nokia phones. Python for Series 60 is just for Series 60 phones; even though the other platforms do run Symbian, they can not run the PyS60 port.
Symbian and Series 60 have some attractive features for developers. First, they are the biggest players in smartphone market. By the time I write this (September 2007) something around 118 million phones have been shipped with Symbian, and most of those are Series 60. The S60 C++ SDK can be freely downloaded from Forum Nokia, so in theory anyone can develop for S60 without spending a penny. Market trends show that Symbian and S60 will dominate the market for 5 to 10 years from now.
That said, S60 C++ development have some downsides. First, the Symbian API is completely different and much more complex to learn than other APIs like Win32 or POSIX -- even though the new OpenC API tries to mitigate this problem. Really advanced development will demand non-free tools, like JTAG debugging. The PC emulator is slow and behaves different from cell phone in many ways.
Series 60 platform has a skewed version numbering scheme. The major version is called "edition", so we have 1st Edition, 2nd Edition and 3rd Edition. Within every edition we have the "feature packs" that are indeed minor revisions. For example, the Nokia 6681 phone belongs to 2nd Edition Feature Pack 2, based on Symbian 8.0. Make sure to query Nokia sites to verify which edition/feature pack your cell phone belongs exactly, because you need this information to determine the right PyS60 package to install.
Developing in Python instead of C++ insulates the developer from most of the problems that he would have in Symbian/S60 development.
Python for S60 can be downloaded from http://pys60.sourceforge.net.
It is a legitimate Python platform in every sense, but there are some details that
the developer should be aware when developing for that target. My experience
with Python for S60 is not that big, but I will try to point the problems I have had.
By the time I developed my first app, I did not have neither the SDK nor the PyS60 UI emulator in PC. Now I have both, and they save a lot of debugging time. And both are free, no excuse not to use them. For some tests, e.g. Bluetooth communication, you can't escape testing in real device.
Since the interpreter runs inside a mobile device, it is inherently more difficult to access the prompt and/or exchange source files. There is an interactive terminal, but both the screen and the keyboard are too limited for serious use. It is mandatory to use the Bluetooth console to do any test in a productive pace.
The PyS60 Bluetooth console is written in Python itself and appears in PyS60 menu. It is important to understand that the cell phone connects to the computer, while the common sense would tell the opposite.
In Windows, you need to create an "Incoming" Bluetooth serial port. It is done done at Control Panel -- Bluetooth -- COM Ports. After you create the incoming serial port and know the COM number, open any terminal app like HyperTerminal, "connect" to the created COM port (e.g. COM5), and then run Bluetooth console inside PyS60. Choose the Windows computer among the Bluetooth connections.
I don't know why, but sometimes it is needed to press some keys in HyperTerminal for the Bluetooth connection to "kick in". Otherwise the cell phone does not find the Windows computer service. Sometimes it is also necessary to try two or three times until the connection is successful. (It seems to be a Bluetooth trait.)
In Linux, the console can be created using the following commands:
sdptool add --channel=10 SP while true; do rfcomm listen /dev/rfcomm0 10; done # On the cell phone, Open "Bluetooth Console" in Python menu and # choose the Linux PC as the machine to connect to # # Once the phone is connected, open another terminal and type screen /dev/rfcomm0
Sometimes the cell phone will not connect to the terminal at the first time, just try twice or three times before checking for problems.
If you are using S60 from the Bluetooth console, bt_discover() cannot be used inside your Python program, since Bluetooth standard has some issues with parallel discovery and communication (in the PC it is allowed by software, but sometimes it drops ongoing connections. Another courtesy from Bluetooth.
Another fun thing about Bluetooth service discovery, is that services offered by servers MUST belong to certain profiles in order to appear in the bt_discover() dialogs. This is not a cell phone problem; the server service must register to SDP this way. The "sdptool" command line shown above does this correctly, using SP (serial port) profile.
I mention that because PyBluez (Python bindings to Linux Bluetooth implementation) did not have this feature until version 0.5 and the registered service did not appear at the cell. After a lot of debugging, I discovered that the phone filters out services with "not for human consumption" profiles. I had to patch PyBluez so the phone could find my server. Now PyBluez brings this feature by itself.
Debugging is a lot more time-consuming than on a regular computer. Try to structure your program to make most of the tests in a PC. And even with this precautions, you will find yourself sending files via Bluetooth very often :)
I was masochist enough to do all tests on the real device. After knowing the emulators available, I strongly suggest the following development cycle:
For the real device testing cycles (unavoidable for programs that use features as Bluetooth, SMS or camera) there is a program called SyncAndRun that automates the upload-execution-debuggind cycle, and it is worth a try. For really serious development, the SDK emulator is the way to go.
A problem I had, was to use several source files (which are portable modules of a system). It was needed to install them as libraries, which rendered SyncAndRun not very usable (when the bugs were in those libraries, meant to be bug-free, but...).
The module updatings pose other problem even if you run you program by calling from Bluetooth terminal: the modules are not unloaded just because the program has ended, because Bluetooth console is itself a Python application and modules are loaded into the same namespace.
A solution I found to work, was to delete modules, import them again, and then forcing them to reload. Otherwise, the reference counter will not evict the old module in time. Since a cell phone is slow, it can be "felt" that only reload() will effectively fetch the new library. Example:
import CLIENT_S60 CLIENT_S60.run() ... error ... ... needs to update face_s60.py library module ... del CLIENT_S60 import face_s60 reload(face_s60) # this one will force reload, # back to top :)
Another solution is to quit Python and load it again (terrible and overkill, but guarantees that no old bytecode is being executed).
If you don't have the SDK, it is probably a good idea to keep all classes in a single file and use SyncAndRun, and separate the components only afterwards.
Symbian OS is 100% Unicode internally, so you should structure your applications to use Unicode strings, like u"bla". If you pass non-Unicode strings to Symbian APIs like appuifw, either it will raise a Parameter Error exception or show garbage characters on screen. (Too bad Python is not 100% Unicode yet.)
This is not an issue by itself, it just gets annoying when you must interact with non-Unicode modules and devices, for example network communication (Bluetooth included) that is byte-wise, and modules like marshal that return regular (non-Unicode) strings.
PyS60 can handle 8-bit regular strings, and convert to/from Unicode and it has all expected codecs (UTF-8, ISO8859-1 etc.) in the distribution. It just does not know how to handle non-ASCII characters that go to the terminal. For example, if you go to the Bluetooth console and type:
print u"á"it is enough to make Bluetooth console raise an exception, because Python for S60 does not know how to convert the string from terminal charset to Unicode.
At first glance, by seeing this error, I thought that PyS60 could not handle regular strings with non-ASCII characters at all. That was embarassing because marshal.dumps() return non-ASCII, regular strings, so how could I transmit that over the wire? The workaround I found was to uuencode this data before sending it over Bluetooth.
Now I know it was a complete overkill. As I said, PyS60 handles regular strings normally, you just can't try to show them in Python console. In the second version of my pet software, I send UTF-8 strings over the wire and convert them to Unicode as soon as I detect a whole data block has been received.
These things are not a problem in Linux because most Linux terminals understand UTF-8.
It is best to use Unicode as much as possible inside your application, because the S60 GUI is pure Unicode. After all, everyone (including Python 3) is going to be 100% Unicode.
e32dbm databases deliver the promise of working the same way as regular DBM Python modules. You can even load anydbm in Series 60, and the e32 backend is automatically selected.
e32dbm is based on e32db, a SQL-based mini storage system supplied by Symbian OS. You can use either, depending on which semantic (DBM or SQL) is more convenient for you.
Since e32dbm is based on a Symbian OS object, it *used* to store and return Unicode strings for keys and attributes. At some moment in time, the API was changed so now (as of version 1.3.19) it returns regular strings as the Unix-based DBM modules do. I guess this change was to make the API more perfectly compatible with the other DBM modules, since the are quite often used in Python. If you plan to run your script in old and new versions of PyS60, you will have to account for this subtle API difference.
The most important module of PyS60 is appuifw, which
gives access to the regular GUI features. It is not difficult to use
(I found it way easier than GTK+ to master and put in good use).
The PyS60 reference mentions that only the GUI thread can deal with appuifw. This is a known constraint for any UI programmer; most UI toolkits impose limits on multiple threads touching UI elements. But in S60, only one particular thread can touch appuifw.
There are no "windows" in the GUI, mostly because the limited screen size. The application body (appuifw.app.body) can hold only one control at a time: either a text box, or a list box, or nothing (None). The picture at left shows a Text field with multicolor messages in it.
Some modal GUI elements can be used above this body: notes (that funny information boxes), queries (typically yes/no questions or choosing in a list), and forms.
The appuifw.Form is (for me) the most powerful modal control, because it can contain several dissimilar fields. Also, there are date and number fields, which saves a lot of time in user input checking (it is very boring to check date and numeric input, even Clipper did it better than most GUI toolkits do today). A form with combo, date, number and text fields is shown in the picture at right.
Another thing is, if you run something from the Bluetooth console, or even via the on-screen console, the UI context of your program is the same as the Python interpreter. So, if you change the title, it will stay that way until Python is closed. The same happens for the exit_key_handler. So it is advisable to save those elements, and restore the old ones when the program ends.
As you would expect, appuifw.app.menu property is where you set the menu items and the menu selection callback.
Following the UI thread constraint, there is a fun object in Python
for S60, inherited from Symbian core functionality: the active object,
a thread "lock" that most UI programs sleep on. For example,
def run(self): self.lock = e32.Ao_lock() self.lock.wait() # restore old title etc. and finish def exit_callback(self): # unlocks the application and lets it finish self.lock.signal()
This is the PyS60 way of waiting for UI events. If the run() function were left to return, the program would close. It is analog to the gtk.main() that returns only when the user quits.
In general, lock.wait() will be called by the primary thread, that is also the UI thread, which is the only one that can touch the UI elements.
The funny thing is, if you e.g. select something on a menu, the i callback will be run in the context of the UI thread. The same thread that is waiting, will also run the UI callbacks. It is not a different thread; so you *can* touch UI in callbacks.
(It remembers a lot the Unix signals. If your program has only the primary thread, it is preempted and put to run the signal handler when a signal arrives. When the handler returns, the thread resumes the normal program as nothing had happened.)
Wait/signal is not limited to one shot in the entire program. In my own program, I used wait/signal to update the journal entry shown in the screen. Anytime something changes, lock.signal() is shot. The wait() is inside a loop, and only exits when self.exit is true.
Since the thread that handles callbacks is the UI thread, the screen will not be updated while you are processing something. For example, if you change the title, the change will not be visible until the callback returns.
To remedy this, just call e32.Ao_yield(), which allows for UI updates. Similar commands exist in every UI toolkit, so it should not sound strange :)
As most UI toolkits, it is important to be careful when using Ao_yield(), because new keyboard events may be processed as well, which could call callbacks! In general, menu options should be disabled, or their callbacks return immediately, while another callback is running.
Different from most GUI frameworks, you can have as much active objects here as you need, and wait()/lock() them as you want. Active objects are the Symbian way to deal with asynchronous events (the same way select() fills this role in POSIX). And almost every task that would demand a kernel-level thread, can be solved with ligher active objects, as good POSIX programs prefer select() to spawn a thread.
Python hides most Symbian active objects, but in C++ they are everywhere. Even reading a file or turning on the camera uses an active object to notify when operation is complete. Asynchronous operations are one of the core Symbian features to save energy.
Python for Series 60 offers a quite impressive portfolio of library modules, given device limitations in size and CPU power. Even uu(encode) and md5 are present!
But you will miss some other modules in S60. These misses need to be dealt with (maybe even by porting the module yourself, which should not be difficult when module is pure Python).
For me, the most notorious module missing is datetime, because a lot of code out there is using it (why such a modern language like Python can't have a native date/time type?)
Anyway, the time module is present and will do date math for you, not as practical as datetime, but suffices. No need to remember the leap year formula ;) By the way, PyS60's time module does not have the timezone property (portable programs should test if it exists before using it). And, since there is not timezone, localtime() and gmtime() return the same tuple inside PyS60.
The 'pickle' module is also missing. I missed this one because I intended to use it to store objects into DBMs and sending Python objects over Bluetooth. The other obvious option for portable communication, 'xmlrpc', is also missing.
You could use 'marshal', but it is NOT guaranteed to be portable and forward-compatible. More important, it is not guaranteed to be safe against corruption (which could allow for network attacks). I ended up making a custom serialization routine for my pet project, it it not as powerful as marhal or pickle, it just handles the basic data types that I need.
Since marshal is not meant to be forward-compatible, I should not mention this ;) but Python 2.4 seems to marshal boolean objects differently from Python 2.2, so I was forced to avoid boolean values.
Otherwise, S60 raises an exception in marhal.loads(), when a boolean object comes from Python 2.4 marshal.dumps(). The other native types (regular strings, Unicode strings, floats, integers etc.) interoperate nicely.
In the 0.2 version of my ctbclient, I ceased to use marshal for serialization, so it is not an issue anymore (for me).
Marshal.dumps() return regular strings even in S60, and these strings can not be converted to Unicode strings, because they are binary (random) data.
This data can be sent over the wire, but can not e.g. be stored in a e32dbm database, since e32dbm accepts only Unicode data, and trying to convert marshal'ed data into Unicode will surely raise an exception.
If you *really* need to store marshalled data in a database, you can uuencode the marshal data. It is ugly but guarantees that e32dbm will be able to convert data to/from Unicode.
Make yourself a favor and use JSON encoding/decoding if you need to store or transmit data. There are several Python/JSON modules in the Internet.
Bluetooth sockets work exactly like TCP/IP sockets; most Python code will accept such sockets happily. In S60, Bluetooth is quite an important protocol stack, so it is natively supported by Symbian and Python. In other operating systems, it is necessary to use non-portable modules (e.g. PyBluez in Linux).
Python for S60 has some socket extensions to support Bluetooth. The most important one is socket.bt_discover(), that discovers services around the phone. I already mentioned that it will *not* work if you are already connected to the phone via Bluetooth. Fortunately you can rig your code to make connections straight to an MAC address/port, to speed up the debugging cycle.
S60 has the select() call but it just accepts to wait for *reading* sockets. It is not even allowed to wait for listening (server-side) sockets. You should use threads if you can not afford to block in socket.send() or socket.accept().
timeout = 30.75 # seconds rd, wr_dummy, ex_dummy = select.select(rd_list, [], [], timeout)
The API signature of S60's select() is the same as in regular
Python, so you *must* pass all socket lists, and receive all
ready lists, althrough only the read lists do something useful.
For those accustomed to TCP/IP and its wonderful reliability: Bluetooth connections fail to establish very often, and it is not uncommon to fail after establishment (at least in my environment where are dozens of Bluetooth devices). So your code should handle socket errors gracefully, otherwise your program will raise exceptions all the time ;) (see picture at right)
In order to know all PyS60-specific modules, the documentation is the thing to be read. But I try to show the major new modules so you'll know where to begin.
The sysinfo module is useful for, well, system information. It has few functions like sysinfo.battery() or sysinfo.imei() (IMEI is the GSM serial number of a phone).
The graphics module is an important module. In general, even the simplest application will import graphics, e32 and appuifw. The most important class inside this module is graphics.Image which allows to load and save images in several formats. The appuifw.Canvas class has the same methods as Image, so you can refer to Image documentation to learn how to use the Canvas.
Another graphics-related modules are gles and glcanvas which give access to OpenGL 3D APIs. Nokia N93 and N95 have accelerated 3D screens so it is really nice to have that in PyS60.
A good source of images is the camera module, which obviously handles the cell phone embedded camera. It is the module we most often employ during public exhibitions of PyS60 :) The examples below talk by themselves:
# Take a photo, show in Canvas and save it
appuifw.app.body = appuifw.Canvas()
img = camera.take_photo()
appuifw.app.body.blit(img)
img.save("E:\\IMAGE.JPG")
# A more elaborate example with a live viewfinder
def viewfinder_callback(img):
appuifw.app.body.blit(img)
camera.start_finder(viewfinder_callback)
# wait for a few seconds to enjoy the viewfinder, then...
camera.stop_finder()
img = camera.take_photo()
appuifw.app.body.blit(img)
img.save("E:\\IMAGE.JPG")
There are a lot of arguments you can pass to take_photo() to select resolution, flash behaviour etc. etc. etc.
The audio module is simple and nice to use. It basically allows to record and/or play sounds. If a telephone call is ongoing, the record and play interacts with the call (i.e. you can record conversations as well as "talk" in an automated way). Example of audio recording:
s = audio.Sound.open(u"E:\\TEST.WAV") s.record() time.sleep(5) s.stop() s.play() # plays last 5 seconds of environmental noise
You can record audio without fears of exhausting the RAM since the audio is always written to mass storage (when you create the Sound object, you need to pass the file name). Provided of course you have a big enough memory card :)
The telephone module supports only two functions: dial(telephone) and hang_up(). The messaging module has two main functions: sms_send(telephone, message) and mms_send(). Such functions are very simple to use but obviously very powerful (and they can make you spend money in telephone bills, so watch out). The position module gives access to GPS (but only Nokia 95 has integrated GPS for now).
The inbox, contacts and calendar give access to the phone's Inbox, contacts list and calendar. In particular the contacts module is not that easy to use but PyS60 at least gives access to those databases, if needed.
PyS60 comes with garbage collection disabled. It employs simple reference counting like Python 1.5 used to be. So, cyclic references will not be collected. Be careful about that, just as if you were using an older version of Python.
Just in case you don't know what is cyclic references, take a look in this piece of code:
class XXX: pass a = XXX() b = XXX() a.xxx = b b.xxx = aWhen the variables a and b go out of scope, they cannot be cleaned by reference counting because they refer to each other, never letting the reference counter go down to zero. True garbage collection takes care of these cases at expense of extra processing (that PyS60 chooses not to do).
The Symbian emulator is another powerful tool to postpone testing on the actual device. This emulator is a strange beast, since it does not truly emulate the cell phone or the ARM processor. The programs to be tested inside the emulator are compiled to x86. Nevertheless, the emulator is slow, CPU and memory-hungry, and is quite different from the true phone.
In order to run Python inside the emulator, you must download the SDK version and unpack it in the EPOC32 folder (C:\Symbian\version\s60_version\Epoc32), which is the "root filesystem" for Symbian emulation and compilation. The Python scripts lie in EPOC32\winscw\c\python folder.
It is important to mention that running Python inside the emulator is very different from running Python for Windows. Inside the emulator, most S60-specific Python modules will work, which does not happen in Python for Windows. Apart from being compiled for x86 processors, PyS60 running inside the emulator really "thinks" and behaves like it was running in a mobile.
If you prefer to use Linux or Mac OS X, you can not use the emulator since it is for Windows only... A VMWare session would help, but you may prefer to test under the normal PC Python by using emulator modules (see next section).
Another way to test the application outside of the phone is to create "emulator" modules, or abstraction modules (I'm still looking for the perfect name). The idea is simple: for example, the camera module does not exist, neither in PC nor in Symbian emulator. So I create a fake module that has the same API, but is implemented in a different way (it could get frames from a webcam or from a static image library).
This satisfies the application that can be tested. When it is running in the phone, of course it would see the "real" camera module and device.
Another even more elegant way to handle the problem is to use a true abstraction module like LightBlue. It offers an uniform API for Bluetooth, whatever you run the script, be it in Linux, Mac OS X or Series 60 phone. The only disvantage is that LightBlue must be installed in phone along with the application.
There is a very nice "emulator" module called PyS60-compat. It emulates the most of appuifw, graphics and e32 modules, so you can test the UI outside of the Symbian emulator. It is a must for whoever can't or doesn't want to use the Symbian emulator (e.g. Linux and Mac OS X users). It needs WxWindows widget library to run, which is also portable.
My personal opinion is that most developemnt and testing should happen in PC and outside of the emulator, since Python for PC is way faster. Once you have tested well in PC, you fine-tune the UI in the Symbian emulator, and then go to the phone device.
S60 3rd Edition is based on Symbian 9.1, which brought a lot of security features. Some of them are annoying for the developer.
In 3rd Edition (3ed), all applications and binaries are signed by a digital certificate. The signing process includes the application capabilities (the system features it has access to) and the scope of distribution (a list of IMEI numbers or "general public" scope).
It is very nice, but the developer must have his certificate signed by Symbian Ltd. Self-signed certificates work to a certain extent, but with reduced capability set and showing ugly warnings while installing. The "official" developer certificate costs about US$ 200/year.
Also, the applications for general public scope must pass a test process in Symbian Ltd., which costs more money. There is a "freeware route" but it has several limitations.
Fortunately, the PyS60 1.4.0 package is signed by Nokia, so it has all the capabilities it needs (all of them, except TCB, AllFiles and DRM). The Python scripts themselves do not need to be signed, since they are just text files.
The need of signing applications will however show its ugly face when we talk about SIS packages and Python extensions, below.
In 2nd Edition phones, it is easy. You can send the scripts as SMS or Bluetooth messages (both end up at Inbox) and a Python Installer offers to install the file in the right place, as a script or as a module.
In 3rd Edition phones, the Python Installer does not work due to the security framework. You must put the script in the phone by other means. There are two ways.
One way is to plug the USB cable to the phone and choose "Mass storage" in the menu. It makes the phone to behave as it were a pendrive, giving the computer access to the memory card's contents. It works under every major operating system.
The problem with this method is that you can only 'see' the memory card (drive E: in Symbian jargon), not the "drive C:" that is the main telephone storage. So you must install Python in the memory card in order to have access to E:\Python folder.
In Windows, you can plug the phone in Nokia PC Suite mode, which also gives access to the cell phone file system and allows you to drag files to it. But PC Suite has the same limitation of not giving full access to the C: phone drive.
The other way is to package the scripts in a SIS file, as we see below.
The SIS file is the best way to deliver Python applications to end users, since they are easy to install, upgrade and remove. Your SIS file can even include the Python SIS package, so the user just need to install one big package instead of three.
In 2nd Edition, just use the py2sis utility that comes with Python for S60 SDK in Windows.
In 3rd Edition, the SIS files must be signed. That would be difficult to do, but now we have Ensymble, a magic Python application that runs on PC and creates 3rd. Edition SIS packages. It works in Windows, Linux and Mac OS X.
A sample package creation command, from my Luca Mobile personal expense controller:
ensymble py2sis \ -n LucaMobile \ # name -r 1.0.1 \ # version -l EN \ # language -s "Luca" \ # short caption -c "Luca Mobile" \ # long caption --caps=NetworkServices+ LocalServices+ ReadUserData+ WriteUserData+ UserEnvironment \ # the capabilities needed by this app LucaMobile/ \ # folder where are the scripts LucaMobile # name of .sis file
The folder where are the scripts (in the example above, LucaMobile/), must have a default.py file that is executed first. Ensymble has other parameters to bundle the Python Interpreter in the package, to specify icons etc.
Ensymble makes use of OpenSSL to sign the package. This is not a problem in Linux but in Windows you will need to download it first and put in the PATH. It is strongly recommended to download the OpenSSL Windows binaries from the STunnel project.
The capabilities specified in the example can be issued by a self-signed certificate (that Ensymble generates automatically if you don't specify a certificate). Some powerful capabilities will demand a true Symbian Ltd. certificate.
PyS60 allows you to make Symbian DLLs in order to extend Python with new bindings. It is a little more difficult than doing extensions in a normal operating system, due to Symbian SDK and API traits, but it is perfectly feasible with standard/free SDK tools.
For 2nd Edition phones, there are several examples of DLL extensios in the Internet, so no need to discuss further. Grab a working example and build your extension like that.
For 3rd Edition the things gets complicated. First, the API is different from 2nd Edition, but it is not that difficult to convert a DLL from 2nd to 3rd. (Ask me if you need a ready-made example, I converted uitricks to 3rd but I'm not sure I can distribute it).
The problem is that 3rd Edition Python DLLs must be signed with the same permissions as the Python interpreter - which mean a lot of capabilities (remember Python is signed by Nokia). Without this, the DLL works on the emulator but not in the phone. The self-signed certificate doesn't cut -- you really need to get a Symbian Ltd. official certificate. (PyS60 1.4.0 doesn't even distribute the SDK libraries for ARM target, I don't know if it is because of this problem, of if it happened by mistake).
A workaround you can use is to get an older version of PyS60, like 1.4.0rc1 or 1.3.22, which is still quite recent. Those versions are self-signed and have less capabilities, so you will be able to make DLLs with the same capabilities (at the cost of not having access to some APIs like telephone, perhaps -- I did not test the self-signed version to verify this claim!).
http://www.mobilenin.com/pys60/menu.htm
http://sourceforge.net/projects/pys60-compat/
http://pdis.hiit.fi/pdis/download/miso/