I am a proud owner of an HTC Hero Android phone. I’ve recently been messing around with one very cool looking application, that allows you to run your own scripts on the phone. This app is called Android Scripting Environment (ASE) and it is truly ace. You can use it to write and run your own Python, Shell (Bash), Lua and Ruby scripts directly on your phone. It also hooks into various Android features, allowing you to make use of various cool Android functions, one of which is getting your location and doing cool things with that information.
I’ve been wanting to get into Python for a long time and I decided that now was a good a time as any. ASE comes with a few sample scripts to get you going, one of which gets the current weather conditions for your current location and speaks it outloud (say_weather.py which calls weather.py). As cool as this is, being told the current conditions isn’t that useful, I wanted to know the forecast for the next day. I thus delved in and did lots of Googling, mainly using this awesome page that teaches you how to parse XML files (which is the format Google delivers its weather forecast info in). The biggest issue was the XML feed from Google doesn’t clarify the difference between the five day forecasts until you get to an actual data reading. The XML feed looks like this:
<xml_api_reply version="1"> <weather module_id="0" tab_id="0" blah> <forecast_information> <city data="Bristol, Avon"/> <postal_code data="bs167eb"/> <latitude_e6 data=""/> <longitude_e6 data=""/> <forecast_date data="2010-04-28"/> <current_date_time data="2010-04-28 12:50:00 +0000"/> <unit_system data="US"/> </forecast_information> <current_conditions> <condition data="Clear"/> <temp_f data="64"/><temp_c data="18"/> <humidity data="Humidity: 52%"/> <icon data="/ig/images/weather/sunny.gif"/> <wind_condition data="Wind: S at 16 mph"/> </current_conditions> <forecast_conditions> <day_of_week data="Wed"/> <low data="51"/> <high data="66"/> <icon data="/ig/images/weather/chance_of_rain.gif"/> <condition data="Chance of Rain"/> </forecast_conditions> <forecast_conditions> <day_of_week data="Thu"/> <low data="46"/> <high data="60"/> <icon data="/ig/images/weather/chance_of_rain.gif"/> <condition data="Chance of Rain"/> </forecast_conditions> <forecast_conditions> <day_of_week data="Fri"/> <low data="48"/> <high data="55"/> <icon data="/ig/images/weather/chance_of_rain.gif"/> <condition data="Chance of Rain"/> </forecast_conditions> <forecast_conditions> <day_of_week data="Sat"/> <low data="44"/> <high data="59"/> <icon data="/ig/images/weather/chance_of_rain.gif"/> <condition data="Chance of Rain"/> </forecast_conditions> </weather>
Now, I know nothing about XML at all, but I found it impossible to get the first actual forecast from the XML data, as each forecast was simply called “forecast_conditions”, using the method in the original weather.py. Thus, after reading the handy tutorial from faqs.org (listed above) I realised I needed to use the nested childNodes function of the xml.dom function that you use in Python to parse XML files.
After lots of trial and error, I worked out the following. A node is a name given to a section named via
. First, you assign a name (in this came dom) to the XML you are reading by doing:
dom = minidom.parseString(xml_response), then I want to get information out of the node. To move through the nodes, you use the following command
dom1Node = dom.firstChild where dom was the name of the original XML file. All this does is move to the first node and give it a name (dom1Node in my case), thus we are now at
. You then use
dom2Node = dom1Node.firstChild to move to the next node and give it a name, thus we are now at
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0">
. Finally, we have got somewhere, because the childNodes (i.e. the ones beneath the node we are at) are the ones with interesting info, such as
and most importantly
. So, finally, we can now assign names to these childNodes that we want. So we use
current = dom2Node.childNodes for the node (the numbering starts at 0 not 1) and
forecast = dom2Node.childNodes for the first forecast. Finally, to get the actual data out of those nodes, we use the following command
data['flow'] = forecast.getElementsByTagName('low').getAttribute('data'). What this does is give the name “flow” to the data element with the Tag name “low” from the “forecast” node that we defined just above. So, essentially, it navigates to and extracts the value “51” from it.
Thus, using this technique, you can get all the forecast data you want. I therefore ended up with this script, forecast.py, to replace the weather.py, to return forecast data:
And I then edited the say_weather.py to say the forecast as well as the current conditions, resulting in say_forecast.py:
The only problem I had with this was that the Google XML feed only appears to give the temp in fahrenheit, not celcius. I can see that you can set the iGoogle to display the temp in celcius, but I couldn’t see how to get that info from a feed.
Now, the next thing on the cards is to make a widget that displays this data on the homescreen. I was thinking of saving the output of the python script to a text file and then make a widget that reads that text file and displays the data. If I can do that, I can then modify the python script to do all sorts of cool things (get news, info from my mythtv HTPC etc).
Sadly, it seems on my version of Android (Cupcake (1.5)) you can’t call ASE scripts automatically via Locale or Tasker, since I get an ASE Force Closed message whenever I try to 😦 So these currently have to be run manually. Still, this is my first piece of Python coding and it was much easier than I thought it would be, once I got my head round it all.