spylib — The Sensorpedia Python Library Comment

Today I’d like to introduce the first iteration of a python library written to ease the process of generating ATOM feeds for Sensorpedia. With spylib, no knowledge of XML or ATOM is required to publish a sensor group, though an understanding of the various tags and what Sensorpedia wants to do with each of them is advised. (The definitive source of this information can be found in the Sensorpedia API.)
Creating a sensor registration document is easy as Py:
myfeed = sensor.SpGroup("efa6e019-eca4-4fd6-a37b-c57ad2b1f441")
myfeed.title = "Cool Sensors near Akron, OH"
myfeed.georss_point = [41.090737,-81.496582]
mysensor = sensor.SpSensor("efa6e019-eca4-4fd6-a37b-c57ad2bFALLS", title = "Cuyahoga Falls, OH")
mysensor.georss_point = [41.166441,-81.536858]
myfeed.addsensor(mysensor)
atomtext = myfeed.toprettyxml()
Some Quick Links:
In this blog post, we’ll discuss the rationale behind the library, and provide a tutorial.
Rationale
Prior to start of work on this library, there were some scripts for the generation of Sensorpedia ATOM Feeds. While they worked fine for internal usage, the programmatic generation of feeds is something that those outside the dev team probably will want to do as well. With that in mind, we started the creation of a library to cover all of the bases needed to deal with Sensorpedia as it stands now in terms of registration feeds.
I chose Python for this library for a few reasons:
- Python is easy to develop with. For those of you who have previously programmed in Python, this goes without saying. The code remains small and easy to maintain. (despite an author who sometimes conceives an imperfect design) Since this is only one project this summer, development speed is nice to have.
- Python is easy to learn. With spylib as the last simplifying piece, creating a complete registration feed should be within the reach of even the most time-constrained sensor admins. When looking at the fact that we won’t be putting out a library in every major language, choosing a language that can be picked up at will becomes important. The hope attached to this library is that a sensor-owning individual with data at his or her fingertips will be able to quickly and easily generate a ready-to-go registration feed.
Though this is just a first iteration, we’ve tried to make things as ‘Pythonic‘ as possible, or at the very least, simple to use.
This is really a pre-beta sort of release, but functionality for all of the currently used SP/ATOM elements are covered and believed to be stable. (As of July 09)
Tutorial
In this example, we will generate a few imaginary sensors based near Akron, Ohio. There will be a discussion about UUIDs and appropriate values for various Sensorpedia fields. If you’re not already familiar with the Sensorpedia API, you may want to open it in another window to reference.
Note: Our discussion of the effects of various Sensorpedia fields is applicable to the current implementation of Sensorpedia as of July 1st, 2009. The definitive source of information concerning how Sensorpedia deals with fields can be found at the Sensorpedia API website
Let’s start by importing the sensor module from the Sensorpedia Python Library:
from spylib import sensor
The sensor module contains a class for individual sensors, as well as one for groups of sensors. To generate a feed, we will need both.
Preparing to Create a Sensor Group
If we wanted, we could create the individual sensors first, but let’s go ahead and start by creating the sensor group. Before we create either a sensor or a sensor group, we need to know the UUID that we will be using. If this is the first time this sensor group is being created, you can make up your own UUID or use the uuid module in python to do it for you:
import uuid
myuuid = uuid.uuid4() #Generates a random UUID
print myuuid
"""589b8e90-3477-4d68-ba52-8cb43824ab5b"""
The UUID is what sensorpedia uses to differentiate between different feeds. If you submit two different UUIDs in otherwise identical feeds, your sensor data will appear twice, which accomplishes nothing of value to anyone. Keeping the UUID the same throughout the life of your feed will make it simpler to manage in the long run. With UUID in hand, we can create our sensor group:
myGroup = sensor.SpGroup(myuuid)
Adding and modifying singletons like title, georss location, etc, is simple:
myGroup.title = 'Cool sensors near Akron, OH'
myGroup.subtitle = 'Do I really need a subtitle?'
myGroup.summary = 'This is an example group of -sensors- created using spylib'
myGroup.georss_point = [41.090737,-81.496582] #This is a Lat-Long pair
We can also use good old fashioned method calls:
myGroup.setgeorss_box([41.0, -82, 42, -81])
An aside about georss_box. Several different uses for the box have been suggested and tried by the sensorpedia dev team. It is best presently to make the box fit roughly around all of the sensors that are in the group.
Turns out we didn’t really want a subtitle, so we can delete it.
del myGroup.subtitle
Some attributes can have multiple instances, and for these we use method calls exclusively. (Instead of data attributes)
myGroup.addauthor("Tim Garvin", sp_uri="http://www.sensorpedia.com/profile?usename=timg", summary="Student Intern")
myGroup.addauthor("My Mother", summary="It's always good to give credit to your mom.")
To add some relevant links:
myGroup.addlink("Sensorpedia", "Sensorpedia.com", "text/html")
myGroup.addlink("The Pythons", "http://en.wikipedia.org/wiki/Monty_Python", "text/html")
We will want to tag our data, to make it easier to search for.
myGroup.addcategory("akron")
myGroup.addcategory("example")
myGroup.addcategory("fake")
At this point, we can generate the xml to see what we have so far. (That is, a sensor group with no sensors)
print myGroup.toprettyxml()
(See tutorialresult1.xml for the output)
Creating Sensors
The sensor group being properly set up, we will create sensors to attach to it. The process is very similar to generating the group object. For this example, we will use the UUID from the group, with a small change at the end:
sensoruuid_one = myuuid[:len(myuuid) - 5] + 'falls'
print myuuid
"""589b8e90-3477-4d68-ba52-8cb43824ab5b"""
print sensoruuid_one
"""589b8e90-3477-4d68-ba52-8cb4382falls"""
You can specify values for the sensor within the constructor. (Note that the SpGroup constructor supports this as well)
falls_point = [41.166441,-81.536858]
sensor_one = sensor.SpSensor(sensoruuid_one,
title = "Cuyahoga Falls, OH",
subtitle="The old homestead",
summary="We don't actually have a sensor" +
" here, but we can pretend like we do",
georss_point=falls_point)
Note that this is exactly the same as creating the sensor with the uuid alone, adding the other attributes separately through sensor_one.title = "Cuyahoga Falls, OH", sensor_one.georss_point = falls_point, etc, as we did with the sensor group.
sensor_one.addlink("Scientific Data from Google",
"http://www.google.com/search?hl=en&q=cuyahoga+falls%2C+oh",
"text/html")
sensor_one.addlink("Even More Reliable Data from Wikipedia",
"http://en.wikipedia.org/wiki/Cuyahoga_Falls,_Ohio",
"text/html")
There are two ways to add content. The first is to add static plaintext content.
sensor_one.addcontent(contentplain = "Cuyahoga Falls is looking good!", contenttype = "text/plain")
We’ll create one more sensor, just for kicks.
sensor_two = sensor.SpSensor("589b8e90-3477-4d68-ba52-8cb43824stow")
sensor_two.title = "Stow, OH"
sensor_two.summary = "Again, not a real sensor. Exists for the sake of example."
sensor_two.subtitle = "Not quite as cool as Cuyahoga Falls"
sensor_two.georss_point = [41.18253,-81.446114]
sensor_two.addlink("Google -- King of all Sensors", "http://www.google.com", "text/html")
In this sensor, we’ll add a link to content instead of the content itself. By linking to content, you have the ability to ensure that the data is always up to date without continually updating the sensorpedia feed.
sensor_two.addcontent(contentsrc = "http://en.wikipedia.org/wiki/File:CuyahogaFallsSign.JPG", contenttype = "jpeg")
Bringing it Together
We will now add our sensors to the group. Note that this in no way finalizes either the sensors or the sensor group. Sensors can be removed, modified in place, and more can be added at will.
myGroup.addsensor(sensor_one)
myGroup.addsensor(sensor_two)
All that’s left is to get the XML document back. XML is currently returned either as a simple python string or a xml.dom.minidom element.
myFeedDOM = myGroup.getfeed() # Minidom element
myXML = myGroup.toprettyxml() # String.
(See tutorialresults2.xml for the result)
This XML is a valid sensorpedia ATOM Feed. If you’re a member of the beta, you can submit to Sensorpedia via the web app or the RESTful API.
(Note: the sensorpedia backend is kind of touchy about the tabs that toprettyxml() uses. toxml() is a safer alternative, but is not as legible to humans.)
That’s it! I hope you find this library helpful in your sensorpedia endevours. Any and all feedback is of course welcome, so let us know how it goes.

