Wednesday, 19 May 2010

N900 Data usage widget for T-Mobile UK

Problem: I need to know how much data I have used on my phone each month so that I do not exceed my 1GB a month allowance.
This isn't easy to see on T-Mobile's website as they provide an itemised csv of usage over the month rather than a lump sum of usage. It would be nice to see a total on the homescreen of my phone (Nokia N900).

Solution: 2 obvious solutions spring to mind:
  1. Monitor data usage on the phone, taking care to not count wifi usage
  2. Get information on data usage from T-Mobile website
Solution 1 would probably be simpler to implement but i'm not quite sure when the month of my contract rolls over accoridng to T-Mobile so I wouldn't quite know when to reset the count every month.
Solution 2 is a more direct measurement of the actualy amount that counts: How much data T-Mobile thinks i've used. I have seen people report discrepancies between the amount of data their phone thinks they've used and the amount of data their provider thinks they've used and solution 2 gets around this problem whereas solution 1 suffers from it. A disadvantage of solution 2 is that it uses some data in the action of measuring the usage.

I chose to implement option 2 because it is the more direct measure and because I had not written much web related code before so exploring this new area would be interesting.

I chose to implement the program in Python as I could do alot of development and testing on my PC and because Python is also well supported on the N900. Again, I have not had too much experience with Python so it was a good experience to expand my horizons in such a way.

Here is the code so far:


tmobile.desktop
[Desktop Entry]
Name=TMobile UK Usage
Comment=Shows you your current monthly usage for T-Mobile UK customers
Type=python
X-Path=tmobile.py

tmobile.py:
import urllib, urllib2, time

def getTotal():
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
    urllib2.install_opener(opener)
    
    login_data = urllib.urlencode({'username' : 'outofdogs', 'password' : 'Bollock5', 'submit' : 'Secure+Log+In'})
    
    f = opener.open('https://www.t-mobile.co.uk/service/your-account/login/', login_data)
    
    data = f.read()
    f.close()
    
    f = opener.open('https://www.t-mobile.co.uk/service/your-account/private/home/')
    
    f = opener.open('https://www.t-mobile.co.uk/service/your-account/private/mtm-load-recent-use/')
    data = f.read()
    textAllowance = data.find('SMS Allowance')
    maxCount = 0
    while textAllowance == -1 or maxCount > 40 :
        time.sleep(0.5)
        textAllowance = data.find('SMS Allowance')
        maxCount = maxCount + 1
  
    text = data.find('Text', textAllowance)
    textCloseBracket = data.rfind('>', textAllowance, text)
    textsLeft = data[textCloseBracket+1:text-1]

    callsAllowance = data.find('Call Allowance')
    calls = data.find('Min', callsAllowance)
    callsCloseBracket = data.rfind('>', callsAllowance, calls)
    callsLeft = data[callsCloseBracket+1:calls-1]
    f.close()
 
    f = opener.open('https://www.t-mobile.co.uk/service/your-account/private/mtm-view-recent-use/?serviceType=mobile')
    f.close()
    
    f = opener.open('https://www.t-mobile.co.uk/service/your-account/private/download-recent-use-info/')
    
    data = f.read()
    data = data.split(',')
    total = 0.0
    for i in range(9, len(data), 7):
        total += float(data[i])
    return (total, textsLeft, callsLeft) 
    

import gtk
import hildondesktop
gtk.threads_init()

def prettyPrint(allowances):
    dataLeft = allowances[0]
    if dataLeft > 1024:
        dataLeft = dataLeft / 1024
        dataLeftStr = str(dataLeft)[0:6] + ' MB'
    else:
        dataLeftStr = str(dataLeft)[0:6] + ' KB'
    retVal = dataLeftStr + '\n' + allowances[1] + ' Texts\n' + allowances[2] + ' Mins'
    return retVal


def refreshTotalsAndLoading(button):
    button.set_label('Loading2...')
    #gtk.gdk.threads_enter()
    while gtk.events_pending():
        gtk.main_iteration_do(False)
    #gtk.gdk.threads_leave()
    total = getTotal()
    button.set_label(prettyPrint(total))
    return

class TMobileUKUsagePlugin(hildondesktop.HomePluginItem):
    def __init__(self):
        hildondesktop.HomePluginItem.__init__(self)
        button = gtk.Button('Loading...')
        button.show_all()
        self.add(button)
  #gtk.gdk.threads_enter()
        while gtk.events_pending():
            gtk.main_iteration_do(False)
     #gtk.gdk.threads_leave()
        button.connect("clicked", refreshTotalsAndLoading)
        #refreshTotalsAndLoading(button)

hd_plugin_type = TMobileUKUsagePlugin

# The code below is just for testing purposes.
# It allows to run the widget as a standalone process.
if __name__ == "__main__":
    import gobject
    gobject.type_register(hd_plugin_type)
    obj = gobject.new(hd_plugin_type, plugin_id="plugin_id")
    obj.show_all()
    gtk.main()


You should follow the instructions on the PyMaemo wiki with regards to where to place these 2 files and which dependecies to install. If the widget does not appear as a choice under 'Add Widget' then try running it from the terminal as in python2.5 tmobile.py and from then on it should appear as a choice.

You should replace YOUR_USERNAME and YOUR_PASSWORD with your My T-Mobile username and password before saving the script.

In order to see your current usagem just touch the icon on your desktop and it should say "Loading..." for 10-20 secs (dependent on your connection speed) and then your data usage should appear as shown below.



I found  this Firefox extension very useful for working out which parameters I needed to pass to the login page.

Obviously, this script is very susceptible to changes in T-Mobile's website but fixing it should just be a matter of making sure the script goes through the same webpages you would go to as a normal user of the site.

Currently, the code is a bit of a mess with no real class structure or seperation of UI from business logic but I'll be looking into threading and signals to the UI in order to improve this and also to make the program more responsive as it currently stops other widgets gtom updating whilst it is grabbing the data.

So I hope this can be of use to someone in it's current state, I do hope to tidy it up and get eventually get it into the repositories. Please let me know if you do use it or just find the code useful as a reference.

Also feel free to adapt the code for other operators. It should just be a matter of providing a different implementation of the (badly named) getTotal() function.

In other news, i finished reading Fred Brooks' Mythical Man Month. It contain must information that is new to me but that's mainly because it's been cited and used by so many other books I've read which shows what a seminal work it is. It was also interesting to see Fred Brooks casually mention the ARPANET project which of course was an important predecessor of the Internet.

Thanks for reading all this way!

Matt