Review: Garmin Forerunner 310XT

I recently purchased a Garmin Forerunner 310XT training device for use while running, cycling, and hopefully swimming. The Forerunner 310XT is a new device from Garmin, and their first multi-sport device that is waterproof and can be used for swimming, and thus triathlons.

For the past several years I have been using a Polar S725X multi-sport training device for both running and cycling. The rest of this review will compare and contrast to the Polar device since that is what I am most familiar. I have not used other GPS-based training devices before, so comparisons with those are left as an exercise for the readers.

The 310XT uses GPS to calculate your location and speed. You can then upload your data via your computer to Garmin’s Connect website, Garmin’s Training Center software, or other third-party options. After uploading you can view a map of your route, categorize and describe your activity. With the Connect website, you can easily share your activity via variety of methods, and even export the route into Google Earth.

Like most of Garmin’s training devices, you can pair the 310XT with a variety of other devices that communicate using the ANT+ Sport protocol. The 310XT will receive and record data from heart-rate monitors, bicycle speed & cadence sensors, foot-pods, and even power meters such as the PowerTap. The collected data is then joined with your route data and transmitted along with it.

The bicycle sensor option from Garmin is a combination speed & cadence sensor that mounts on the rear chainstay. This design allows one sensor unit to have two separate magnets for both the crank and the rear wheel. Compared to the Polar solution, this is much cleaner and easier to mount than two separate sensor units. The Polar cadence sensor, especially, is difficult to mount on some of the modern carbon downtubes, so the Garmin solution is a welcome change.

The speed sensor augments the GPS data so that accurate speed is recorded even when GPS signal is not available or accurate.  Garmin also sells an optional foot pod sensor that accomplishes the same when running without GPS signal, such as inside on a treadmill. I haven’t used this sensor yet as where I have run has had great GPS reception thus far.

I used a foot pod sensor with my Polar to keep track of my speed and distance while running. The downside of this type of solution is the relative inaccuracy of the data. I’d often see 10 to 20% margin of error, even after calibrating the foot pod.

My concern with a GPS-based training device would be the accuracy of the signal, especially when running under under a lot of foliage. So far, the 310XT has proven itself more than capable in this regard, and much better than other GPS devices I have used in the past. Viewing the recorded route data I’ve found very little error in position so far, and only a little bit with elevation, even when running underneath trees and bridges.

Like all GPS devices, the 310XT must determine its position when it is powered on. If you start up the 310XT inside, or where there is poor GPS signal, it can take a very long time to determine initial position, if it all. This can be an annoyance when you’re ready to start your training and you don’t have a solid 3-dimensional fix yet. The 310XT lets you begin your timer and start your activity before it has GPS signal, but it can sometimes take surprisingly long to get that initial fix. Another disadvantage of not having a fix is you won’t have accurate local time until then, either.

The Garmin 310XT has a rechargeable battery, but battery life is only approximately 20 hours of usage. My Polar S725X, by comparison, has a watch-style battery that has lasted over 5 years. In practice, a rechargeable battery solution works great, but may present a problem on multi-day activities where there is no opportunity to recharge.

Transmitting the data from the training device to your computer is done via a USB dongle that uses the ANT protocol. Garmin provides drivers and software for both PCs running Windows and Macs running OS X. The Polar solution uses an infrared based receiver that is much more difficult to work with as it requires line of sight between the training device and the infrared receiver, and Polar does not provide a software option for Macs.

For most users, Garmin’s software solutions are stellar compared to Polar’s. The big win here is Garmin’s Connect website which allows you to easily view your data online, share it with friends, and upload your data from a variety of different computers. Sharing your data is trivial, and allows your friends to view your routes, as well as being able to search for routes from others near you. The Connect website represents a modern solution for the social Internet, a great solution for most users.

Where the Polar software shines is for advanced heart-rate based training, especially with coaching assistance. Polar’s software is designed to easily share your data with a coach and receive training programs with them. Additionally, both the software and the Polar device have much more advanced features for heart-rate based training. For example, with the Polar I can run several tests to determine if I am over-training, or even what an estimate of my current VO2max. The Garmin solution only has different heart rate zones, more than adequate for most users, but you do get the impression the Polar has more science behind it.

The 310XT supports multiple bike settings, each with its own odometer. I find this feature in particular compelling as I like to keep track of my mileage for each bike separately, and as far as I could tell the Polar S725X always combined bike mileage for all bikes it had configured, rather than a separate odometer for each one. With the GPS based tracking, you don’t even necessarily need a speed/cadence sensor and you can still keep track of your bike’s mileage. This is especially compelling for mountain biking, where the rough trails often render a traditional bike computer useless.

So far, the Garmin Forerunner 310XT has been a fantastic training tool and I haven’t missed using the Polar S725X yet.

Connecting to Apple Push Notification Services using Python & Twisted

One of the exciting features of the upcoming iPhone 3.0 operating system is the ability for a device to receive a notification message from your own application that is relayed by Apple’s network cloud. This feature allows the iPhone to channel all out-of-band communication into a narrow channel that is low impact on the device from a power, security and usability point-of-view.

As an application developer, you are responsible for two pieces to make this new notification service work: the actual application that runs on the iPhone OS, and a provider service that both communicates with the device and directly to Apple’s cloud.

In a typical flow, the application on an iPhone device issues an API call to request notifications for the identifier that the developer has assigned to the application. In response to that API call, Apple’s servers provide the device with a binary token value that uniquely identifies the device & installation combination (for security reasons, the device token is reset if the device is reset, so it is not a one-to-one mapping to the actual hardware). Next, the application must connect to the developer’s provider servers and provide it with the device token it has received from apple. The provider can now use the device token when communicating back to the Apple Push Notification Service (APNS) cloud.

A provider implementation has very little work to do to inform APNS of a device update. Most of the effort in a provider will be in the actual framework of the application itself, and managing what information should be sent to a device. A common implementation will be for a provider to both communicate with the APNS server cloud and also to the application’s own network services and effectively become a protocol translator. Such a heavily network based application like that is a perfect match for the Python language and the Twisted framework.

A provider to APNS link is very simple: a secure-socket connection (SSL) is made to a APNS server and then simple messages are sent by the provider whenever a notification needs to be sent to the device. The APNS server does not respond or acknowledge the message. Every so often (Apple recommends once an hour), the provider server should connect to a web server that will dump a list of device tokens that are no longer valid (as in the device has uninstalled the application). This is the provider’s only feedback mechanism outside of communicating directly with a device.

The first step is to setup an SSL connection to the APNS servers. By following the directions on Apple’s developer portal, you can create a certificate and private key that are assigned to your application identifier. This certificate & private key must then be used when connecting to the APNS servers as an authentication mechanism.

One caveat  - the Mac OS X Keychain Access application does not directly export certificates and private keys in Private Enhanced Mail (.pem)  format, which is what the OpenSSL implementation we use with Twisted will want, but luckily there’s an easy mechanism to convert if you export the files as Personal Information Exchange (.p12) format. The following two commands can be used to convert the .p12 files into .pem files using the built-in openssl command on Mac OS X or most Linux distributions:

openssl pkcs12 -in cred.p12 -out certkey.pem -nodes -clcerts
openssl pkcs12 -in pkey.p12 -out pkey.pem -nodes -clcerts

Now that we have our SSL files in the proper format, we can build our ClientContextFactory object that will be used by Twisted to initiate a connection to the APNS servers:

class APNSClientContextFactory(ClientContextFactory):
    def __init__(self):
        self.ctx = SSL.Context(SSL.SSLv3_METHOD)
        self.ctx.use_certificate_file(APNS_SSL_CERTIFICATE_FILE)
        self.ctx.use_privatekey_file(APNS_SSL_PRIVATE_KEY_FILE)
 
def getContext(self):
    return self.ctx

We’ll also need a ClientFactory object that will be used to build the Protocol object whenever a connection is established to a server:

class APNSClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        print "Connected to APNS Server %s:%u" % (addr.host, addr.port)
        return APNSProtocol()
 
    def clientConnectionLost(self, connector, reason):
        print "Lost connection. Reason: %s" % reason
 
    def clientConnectionFailed(self, connector, reason):
        print "Connection failed. Reason: %s" % reason

Next, we’ll need the actual Protocol object that will format messages and queue them to the server. For APNS, we don’t receive any responses so that half of the protocol goes unused.

class APNSProtocol(Protocol):
    def sendMessage(self, deviceToken, payload):
        # notification messages are binary messages in network order
        # using the following format:
        # <1 byte command> <2 bytes length> <2 bytes length>
 
        fmt = "!cH32sH%ds" % len(payload)
        command = '\x00'
        msg = struct.pack(fmt, command, 32, deviceToken,
                          len(payload), payload)
        self.transport.write(msg)

And finally, we’ll need the main code to kick everything off for the test:

if __name__ == '__main__':
    reactor.connectSSL(APNS_SERVER_HOSTNAME,
                       APNS_SERVER_PORT,
                       APNSClientFactory(),
                       APNSClientContextFactory())
    reactor.run()

From here, the Python and Twisted combination can be easily extended to handle multiple protocols and convert between them as needed. For example, one of the commonly expected use cases of the new push feature will be instant messaging (IM) clients that will need to provide a proxy between the device and the IM servers and the APNS servers in order to notify a device of outstanding messages.

The full Python script containing the above excerpts can be downloaded here:

test-apns-blog

iPod installation in the car

Due to recent negative events with XM Radio’s customer service, I no longer have an XM subscription in any of my vehicles. In the truck there is an auxiliary input jack, so feeding music from an iPod is a no-brainer. But in the Corvette, there was no such option. GM never really provided a great solution for it, but luckily the aftermarket came to the rescue.

One of the better options is a device called the Lockpick that intelligently interfaces with the various radio interfaces in GM vehicles. The Corvette Lockpick they provide interfaces directly with the navigation radio in all 6th generation Corvettes so I ordered it to try it out.

Installation turned out to be incredibly simple. The unit ties into the wiring harness that feeds the XM Radio brain. In the convertible model, the brain is hidden behind the waterfall, located between the seats. Removing the waterfall is straight-forward, and then you are left with a simple wire routing problem.

In the end, I decided to locate the Lockpick unit itself on the carpeted area behind the waterfall. I used sticky-tape velcro to keep the unit attached to the carpet, and then ran the wiring harness to the XM Radio unit in order to attach the Y-connector that feeds into the Lockpick itself. The wiring harness that connects to the iPod also has to be routed, and I decided in the end to locate the iPod in the glove box rather than the center console. Access to the center console would require some cutting for a clean installtion look, and plus it tends to get rather hot inside so I was worried about shortening the life of the iPod a bit too much to locate it there.

Luckily the glove box had a space for a switch that wasn’t installed with my option packages, so it made a perfect place to feed the wiring harness. From there, I routed the wiring harness into the dash and then underneath the center console and feed it directly to the waterfall area. The final result is a perfectly clean and hidden installation with no permanent modifications needed to the car.

The Lockpick unit itself works great, although the control system is a quirky. The lower right-hand button in the XM Radio menu activates the iPod. Once activated, the Category up and down buttons control your playlist selection, and then seek forward and back buttons control the current song playing within the playlist. The info button displays the song information as you would expect. It’s quirky, but works extremely well.

One Year at Zenoss

Yesterday marked my one-year anniversary at Zenoss. When I decided to take the job at Zenoss I knew it would be a challenging position, and time has proven this assumption correct. The new (to me, anyway) technology, the remote work environment and the realities of a startup company with limited resources have all added their own challenges to the job.

I found the Zenoss product itself to be more mature than I had expected. While it still has plenty of rough edges, especially in the user interface, it is a rather feature-rich application with a very large user base in both the free community and paid enterprise versions. There is a tremendous amount of work left to do on the application, but with each version we see a significant step forward and an expanded user interest because of the changes.

When I came to Zenoss, my new co-workers and I brought with us a culture of using agile development methodologies and processes to the company. We expected, and were asked by company management, to implement those processes at Zenoss. Over the past year, we have seen the right things happen from this shift in engineering culture:

  • development time has become more predictable
  • planning and priority selection take a much more important role than ever before, and not just in engineering (in fact, most importantly not in engineering, but at the executive level)
  • quality assurance is now a fundamental part of the engineering process, not a luxury for later
  • code and design quality has improved dramatically as the engineering team begins to understand how much control they really do have over the process

There still remain many challenges, but these are the same ones I have seen with all teams that struggle with the discipline needed for agile methodologies. Effectively breaking down large development tasks into two-week iterations remains a hurdle; I suspect at a fundamental level many of the developers do not fully believe this is possible, which is a long, long discussion. There was also a reluctance, until recently, to fully engage with teammates on performing effective code and design reviews. These will both improve over time as the team matures.

When I first started at Zenoss there were 5 developers in Annapolis, 2 developers in Austin and me , usually working remote in Houston. Since then, the team dynamics have changed so that I and one other developer are remote most of the time, 3 developers are full-time in Austin and 1 in Annapolis. This team dynamic change has made the infrastructure needed to support remote development much more important, but at the same time it has made the remote developers somewhat more isolated since a bit more now happens only in one location. Since I travel to Austin frequently I can avoid the worst of this unavoidable trend, but it will likely always remain a challenge as long as we have remote employees.

On a personal level, working remotely full-time for this long has been much more difficult than I expected. I last did this much remote work in the mid-90s, and it was difficult to do then, as well. On the surface, I spend all of my work hours focused on some problem on the computer, but in reality much of my job is very social and without face time it starts to wear on me very quickly. Frequent visits to Austin help tremendously, but in reality this will likely always be an issue until I relocate.

I’ve encountered almost all of the traditional problems people have while working at home, but especially keeping focus and balancing the time spent between work and home life. Focus is purely a self-discipline issue, but it is remarkable how much of this is provided by the routine of commuting to an office. Maintaining a good work-life balance is also tremendously hard when working at home, unless you dedicate a specific place in the house for work. It took a few months to really learn this lesson but eventually I bought a second desk and made myself an office separate from my normal home office. Before then, I found it way too easy to bring my laptop into the living room and I’d continue to check e-mail and work on problems throughout the evening. Sometimes, I still do, but not at least it is not a mindless occurrence.

Zenoss is a very small company, and naturally we have very limited resources. Of course, today’s economic environment makes this true for almost every single company. But more specifically, I find ourselves working around what effectively is a lack of resources in our IT department. I often have to build my own virtual machines at home, or buy little widgets to help productivity because I am remote. At some level, I don’t mind this, since it’s nice being able to actually work somewhere you can do this, rather than being told you can’t.

After a year, I’m still not a huge fan of the Python programming language, but I’ve come to accept it and I can be productive with it. Working with it feels a whole lot like I stepped back in time 15 years, and saying that is a great way to start an argument, so I’ll just leave it at that.

One great surprise from the past year is that I became the guru for Zenoss’s Windows monitoring technology. We have a custom implementation of MS-RPC that is based upon the Samba 4 source tree. On top of this layer, we have provided our own implementations of the DCOM, WMI, and Windows registry interfaces so we can call these services directly on any Windows device. This is a great feature, as it allows us to communicate directly to Windows devices from our Linux based product, without requiring a Windows device to be running our software just to provide Windows-based connectivity, unlike some other systems management products.

Over the next few months I will be taking on more and more of the implementation of the new Zenoss user interface, which is a great project that should dramatically improve the user acceptance of quality of the application. It also gives me more time to work on user interfaces, which is always an area of software development I enjoy but rarely get a chance to do.

Secure Windows Monitoring with Zenoss

Starting with version 2.3.x, Zenoss can monitor computers running Microsoft Windows with a variety of data collection protocols: SNMP, WMI over DCOM/MS-RPC and Perfmon over MS-RPC.

In Zenoss Core, the status of Windows services and the Windows Event Log are monitored using Windows Management Instrumentation (WMI) queries over the DCOM/MS-RPC protocol. In the implementation of MS-RPC that Zenoss is based upon, authentication credentials are sent to the remote server using the Windows Challenge / Response (NTLM) mechanism. Using this authentication mechanism, the actual password is never sent across the network, but rather the server produces a “challenge” value that the client must calculate using the password rather than sending it across the network.

NTLM authentication is the same mechanism that Windows devices themselves use for client/server communications, such as file sharing and remote administration.

Starting with version 2.3.x, Zenoss Enterprise gathers Perfmon data using the remote Windows registry API over the MS-RPC protocol. This technique is both more efficient and secure than the previous one. The same authentication mechanism used by Zenoss’s WMI library is used here, providing the same level of security.

Prior to version 2.3.x, Zenoss Enterprise used a different mechanism to collect Perfmon data from Windows devices. This mechanism used a utility known as winexe to remotely execute commands on the Windows device (in this case, the typeperf.exe Windows utility). Unfortunately, the winexe utility sends the username and password used for authentication across the network in clear text, providing a less than ideal configuration for security.

Zenoss users monitoring Windows devices should be running version 2.3.3 or newer for the best possible security when communicating with those devices.