Showing posts with label HRM. Show all posts
Showing posts with label HRM. Show all posts

Saturday, April 20, 2013

Connecting to the Polar Personal Trainer Site

Connecting to the Polar Personal Trainer Site

A number of people have requested access to the comms code that I use in the Polar HRM Uploader tool I created.  Because of this, I've decided to write about the software here and offer it free for non-commercial use.  It's not a complete implementation, you will still need to write your own HRM readers and convert that to the Polar format, but the attached code should give you a good starting point.

The communications protocol has been reversed engineered by intercepting the communications between Polar's WebLink and the Polar Personal Trainer Site.  I used an intercepting proxy, called BurpProxy, that does a great job of displaying the content of HTTP traffic.  Luckily, the Polar protocol is in plain text so it makes it relatively straightforward to determine what is required.

Click here to download all the source files in one archive. The code is also on GitHub

The Communications Protocol

Uploading to the Polar Site is a three stage process:
  1. Login.  This stage requires that you authenticate with the Polar site using a basic-auth method.  You can see an example of the login handshake here.
  2. Upload the timestamps of HRM files.  The Polar site will then validate the files and return a response which indicates which files have already been uploaded.  You can see an example of the timestamp handshake here.
  3. Upload the files.  The files are uploaded using a simple XML format.  You can see an example of uploading files here.

XML Marshalling

Since we need to convert from Java to XML, we use an XML data binding library called Castor.  Java has come along way since I originally wrote this code and you can now use Java's JAXB reference implementation to do something similar.

There's a number of good examples on the Castor site that shows how to use the libraries.

Click the link to get the Castor mapping file that I've used.

The code below shows a snippet of the XML format used by Polar.

 <wristunit-data>  
     <prop name="subModel">166</prop>  
     <prop name="version">2</prop>  
     <object name="userSettings">  
         <prop name="maxhr">186</prop>  
         <prop name="resthr">50</prop>  
     </object>  
     <collection name="Exercises">  
         <item type="Exercise">  
             <prop name="origin">1</prop>  
             <prop name="time">2011-08-22 17:39:52.000</prop>  
             <prop name="save">True</prop>  
             <object name="mode">  
                 <prop name="speed">True</prop>  
                 <prop name="cadence">True</prop>  
             </object>  
 ...              
   

We represent each element with a Java object:
  • Property.  These are the core elements on the Polar message that describe a name and value.  They have an optional type.
  • Item. An Item is a collection of Polar objects and it has a Type and an optional Index.
  • Collection.  A named list of Items, e.g. exercises.
  • Polar Object.  A named collection of Properties.
  • Wrist Unit Data. A wrapper object for the message.
  • Webservice.  A wrapper object for the Polar response.
You can download these files by clicking on the links or view them on GitHub.

Communications Code

The communications code is based upon standard Java HTTPUrlConnection and is contained in the class PolarSiteConnection.  This contains simple methods for connecting to the Polar site, sending data and parsing the response.

It encapsulates the Castor data binding too, which is adequate for my project but not generic enough as there's no easy means of implementing an alternative library without some refactoring of the code.

Here's a simple example of how to use the code to login:

 private void processLogin() {  
         // Update the status on the main dialog.  
         controlledFrame.setStatusMessage("Logging into Polar website...");  
         // Get the dialog credentials and try to connect.  
         String username = loginDialog.getUsername();  
         String password = loginDialog.getPassword();  
         System.out.println("Site connection is: " + siteConn);  
         // Pass these to the connection class.  
 ****  
         Webservice ws = siteConn.intiateConnection(username, password);  
 ****  
         if (ws == null) {  
             controlledFrame.setStatusMessage("Cannot connect to Polar site");  
         } else {  
             Status s = ws.getStatus();  
             if (s.isOK()) {  
                 userPreferences = ws.getUserPreferences();  
                 controlledFrame  
                         .setStatusMessage("Logged into Polar website as user "  
                                 + userPreferences.getFirstName() + " "  
                                 + userPreferences.getLastName());  
                 setAppState(AppState.LOGGED_IN);  
             } else {  
                 controlledFrame  
                         .setStatusMessage("Cannot log into the Polar website.");  
             }  
         }  
     }  

Note that the variable siteConn is an instance of PolarSiteConnection. The lines wrapped in **** are the interesting bits that send data to Polar.

PolarSiteConnection also uses a library to convert the password to Base64 as part of the Basic-Auth authentication.  You'll need to source your own copy of this as the licensing around the one I use prevents me from distributing it.





Thursday, November 03, 2011

Uploading Old Polar HRM Data to the Polar Personal Trainer Website

(Update 22nd April 2014: Newer version of the HRMUploader jar fixes an issue with HRZones if there are more than five defined in the HRM file)

I'm a keen cyclist and have used a Heart Rate Monitor of various descriptions for a number of years. I've religiously downloaded this data onto the PC and stored it in the various applications that come with the monitor. Not that I do anything with it, though I did get part way through writing an application to store the data in a relational database and then display multiple rides overlaid on one another for visual comparison. Anyway, I digress.

More recently I've bought Polar HRMs, they are great products with useful features for cycling. Years ago I wrote a Java application that converted the 'other' HRM files to the Polar format, so that all rides and associated HRM data could be shown in the latest Polar application on the PC.

Polar have caught onto the web, and have launched a site that allows you to transfer your data from the HRM to the web. Great for current stuff, but what about all those old files I have? In their wisdom, Polar have not released a tool that allows me to upload the data I've got on my PC.

There are a few people around who would, like me, prefer to have all their data on the web, and want to upload their old data. Being a professional Java developer, I thought it would be a doddle to create a Java Application that interfaced with the Polar web site and allowed me to transfer my data. And, in general, it was. So here is a Java application that does this. It's a little crude, but does the job.

Just run it with:

java -jar HRMUploader.jar


Enter your Polar Personal Trainer userid and password. If you log in successfully, then you will see your name in the lower status pane.

Browse to your polar .hrm files and select one or more (try it with one first :) ) The application will check the site to see if it's already uploaded a file for this date. If it has, it will put a check mark against the file, if it hasn't then use the upload button to upload the file. It won't upload a file that is already on the site, you will have to delete it from the site if you want to resend it.

There are no guarantees that this will work for you. Might be worth opening another 'test' account on the Polar site and trying it out there first. Whilst you can select many files to upload at once, it might be worth limiting it to 10 or so at a time - the Polar site might choke on too many. I just tried it with about 70 and it took a while, but seemed to work.

Regarding calories expended.

This value is read from the associated PDD file and needs to be in the same directory as your HRM file.  There's one PDD file for each day, so you could have many HRM files that reference the same PDD if you do multiple exercises per day.  In these cases, you are unlikely to be able to read the PDD as it will not have the same name as the HRM file.  Unfortunately, when I originally wrote the HRMUploader, I didn't realise I needed to read the PDD too.  Ideally I need to change the application to read the PDD first,  since this contains all the HRM file names.  However, I'm not planning to do this any time soon, sorry.

Altitude data

Altitude data is sent to the Polar site in 'feet'.  This means that if you are using meters in your HRM file, then the conversion to and from feet could result in a rounding error.

Furthermore, I seem to recall a bug in the HRM files that stores altitude as feet, even though the file is supposed to be metric.  Send me a HRM file example if you suspect the altitude is being uploaded incorrectly.

Here's the code to interface with the Polar site

At some point I'd like to host this on the Google Java App Server, but they've done some funny stuff with Java and restricted various classes in the default 'JRE'. It means that some stuff which should work under Java's WORA mantra doesn't.

The application uses various libraries from Apache, Google and Castor. All their respective rights are recognised. The software is supplied 'as-is' and you use it at your own risk. You did back that data up, right?