Hacking Polar Watch WebSync Software
I recently purchased a Polar FT-40 watch to monitor my fitness level and track my workouts better. I like the watch so far although I’m not ready to give a thorough review on it just yet. Today, I received the Polar FlowLink data transfer unit that allows me to transfer the data on my watch to Polar’s website. It allows you to chart your progress and do all sorts of interesting things with the data. I was surprised how easy and smoothly the software worked. However, I wanted the data on my desktop so I could do more with it. I wanted to provide my own charts and data views in Excel. I wanted to be able to post it to my blog easily or write a WordPress widget to display my data. That said, I decided to look at what the WebSync software was written in. I had a sneaking suspicion that it might be .NET — I was right!
So, I decided to look under the hood and see if I could tackle writing my own front end to their devices. What I found should horrify anyone who has ever read past Chapter 1 of a reasonable “C#” book.
I started by pulling in the obvious assemblies to see what was built. The project looked reasonably well built. There was enough evidence ot see that there was at least SOME design put into the application. I even found some tests in tone assembly — at least there were some tests (checked that off on their requirements eh?). When I took a look at the EXE, however, what I saw shocked me. So I started drilling down into WebSync.exe. I found a Polar.WebSync.Program class with a static Main() method. Bingo – my entry point. I immediately saw some minor concerns. For instance, they were using a Mutex to provide the functionality of a Singleton pattern. Worse yet, they were calling GC.KeepAlive() on the Mutex. Interesting. They did, however, have what looked like an external exception reporting framework, so that at least gave me SOME hope.
I found Application.Run that was starting a new WebSyncTrayForm() so I naturally followed to the form constructor. In a big Try/Catch block (with no code executing in the “catch” portion), I found a TextBox-style TraceListener was added to the form — mmkay. That’s a decent idea I suppose, but let’s look at the form’s Load event. Oh my! I closed my eyes and looked again. I closed then and then looked one more time. Oh, these folks must have written some VB code with “DoEvents” called more than a few times in their past history. Tell me what you see wrong with this:
WARNING: Not good example code!!
private void WebSyncTrayForm_Load(object sender, EventArgs e) { base.Visible = false; this.notifyIcon.Tag = this.notifyIcon.Icon; this.toolTip = this.notifyIcon.Text; this.notifyIcon.Text = this.toolTip + "\n" + Resources.StatusInitializing; this.timerDaemon = new Timer(); this.timerDaemon.Interval = 0x2710; this.timerDaemon.Tick += new EventHandler(this.timerDaemon_Tick); this.timerDaemon.Start(); this.timerDaemon_Tick(this.timerDaemon, EventArgs.Empty); }
Seriously? These guys set up a timer, and then start it, and then MANUALLY call the Tick function they just set up! (how do they know it hasn’t been executed already between the start call and a thread interuption that might have caused the Tick event to get executed next.
Then I looked at the tick event and I couldn’t believe what I was seeing.
WARNING: Not good example code!!
private void timerDaemon_Tick(object sender, EventArgs e) { this.retryCount++; try { if (this.retryCount == 6) { this.timerDaemon.Interval = 0xea60; } this.mounter = new WristUnitListener(); this.mounter.WristUnitMounted += new WristUnitConnectionEventHandler(this.WristUnitMounted); this.mounter.WristUnitUnmounted += new WristUnitConnectionEventHandler(this.WristUnitUnmounted); this.mounter.Start(); this.DoInitialConfig(null); this.timerDaemon.Stop(); this.timerDaemon.Dispose(); this.timerDaemon = null; this.notifyIcon.Icon = this.notifyIcon.Tag as Icon; this.notifyIcon.Text = this.toolTip + "\n" + Resources.StatusRunning; Trace.WriteLine("Connected to Polar Daemon.", "WebSync"); } catch (ConnectionException exception) { if (this.retryCount < 6) { Trace.WriteLine( string.Format("Couldn't connect to Polar Daemon ({0})", exception.CodeString), "WebSync"); } if (this.retryCount == 6) { Trace.WriteLine( string.Format("Couldn't connect to Polar Daemon ({0})", exception.CodeString), "WebSync"); Trace.WriteLine( string.Format("WebSync couldn't initialize properly." + "Please check that Polar Daemon service is running.", new object[0]), "WebSync"); this.notifyIcon.Icon = Resources.IconExclamation; this.notifyIcon.Text = this.toolTip + "\n" + Resources.StatusInitError; this.notifyIcon.ShowBalloonTip(0x2710, Resources.ToolTipProblemTitle, Resources.ToolTipInitError, ToolTipIcon.Warning); this.notifyIcon.BalloonTipClicked += new EventHandler(this.notifyIcon_BalloonTipClicked); } } }
OK. These guys are on crack! They have a retry counter that apparently will never be more than 1. Because the tick event will go away and there is no loop in this code, the retryCount will always be 1 (taking note that they decided to start with a 1-based counting system rather than zero because n-1 is a bit complex). That at didn’t stop them from checking to see if it was equal to 6, and if so, changing the interval.
In the tick event, they create a new instance of a WristUnitListener and hook up events to it EACH time. They call start on the WristUnitListener instance and then STOP the timer and dispose of it! Never mind the fact that this timer execution is owned by the main thread rather than the timer tick function — when a timer stops itself, disposes of itself, and then nulls itself, it’s time to reevaluate your understanding of background-thread polling. This is insane! I have no idea how this even works. I can only hope that, as I dig in further WristUnitListener actually works the way it is supposed to and the only thing that sucks is the WebForms code.
Update January 13th, 2010 1:15AM PST:
I was able to successfully hack around with the API and get data off the watch with little effort. The trick was to working around some wonky and non-working APIs. To their defense 1) this API and software has to work with multiple watches 2) wasn’t intended to be consumed by other devs 3) was written with interop for the native libraries accessing the hardware, 4) does show signs of some intelligent thinking (although does need considerable amounts of re-work). As you can see by the image, I can even pull the bitmap logo off of the watch and, if I so desire, set it.
This is far from complete but I will work it over some this week and this weekend before publishing the source on Codeplex. Let me know if there is something in particular that you’d like to see.
Update July 7th, 2010 12:01AM PST:
I have posted this code to codeplex as-is. You can find it here: http://polarsync.codeplex.com/
If you would like to contribute source code or improve the project for others in the community, please send me a request and I’ll approve you. I don’t intend to maintain the code or improve it.
Related posts:


These postings are provided "AS IS" with no warranties, and confers no rights. The content of this site are my own personal opinions and do not represent my employer's view in anyway. In addition, my thoughts and opinions often change, and as a weblog is intended to provide a semi-permanent point in time snapshot you should not consider out of date posts to reflect my current thoughts and opinions.
Is there anywhere in the code for the upload settings – trying to get the software working via a proxy server is a nightmare as there is nowhere to set username and password for the proxy to use.
Is there somewhere in the code to hack out a config file for this do you reckon ?
Tobin,
You are my hero. That was awesome. I’ve never even thought of hacking my watch.
Hi
where can I find your version – I’m very interested in it?
THX
You rock!
I was looking into it as well… and I’m also trying to find a way to make it work on a mac.
I might write my own driver and get rid off de Polar SW altogether. Being it .NET makes that a little easier ;o)
Thanks, man.
There are a lot of people screaming for a way of getting access to their raw polar hrm data… Great to see someone doing some work in this area…
If there is anything I can do to help I’d be happy to do so
Thanks everyone. Seems to have been a lot of sudden interest in this topic this week. I will post my code tonight on codeplex and try to get something better out soon. I haven’t touched the code since January however so I’m not certain if it is useful for anyone else. It will provide at least a starting point, I think.
Hi!
Did you put it on CodeP? I can’t wait.
I’m going to use it with my RS300X and 3rd party software becouse I don’t like idea to put my personal data on their servers nor to use their web apps.
You’re great!
Cheers,
Matija
Hi
I’m thinking of buying a Polar heart rate monitor and was looking around if I will be able to get the data to my computer instead of their website. I’m glad that I found your site but unfortunately I couldn’t find the code on codeplex. Would you mind providing us with a link?
Hi,
This looks good, but I’m not a coder and don’t understand all the jargon.
I need some way of getting my data off my Polar RS300X when I’m offline.
Can you help?