Zephyr HxM BT

A new toy arrived in the post this morning. Eric Morse from TitanXT very kindly arranged this for me as a thank you for building the Tracks2TitanXT Android application.

image

I’ve been after one of these for a little while after getting a look at one when a couple of colleges bought them to help with their training.

As well as heart rate information the unit contains an accelerometer which is used to generate cadence information, this means that it can be used to approximate distances where there is no GPS reception. The data to is passed to a mobile phone via Bluetooth and there are a number of applications that understand the data including My Tacks. There is also an opensource project called zephyropen on goolge code that has documented the protocol and created a desktop app to display the data.

Zephyr also do a smarter version of the HxM called the BioHarness, this version gathers skin temperature and respiration rates as well as all the data from the HxM.

My Tracks only collects data from the sensor while it’s recording a route and it’s not easy to see the data once the workout has finished so I’m tempted to write a little app to grab the data at any time and possible a tool to view the data stored in the My Tracks database. I’ll also look at adding average heart rate info to the workout summary Tracks2Miles can upload to dailymile.

image

The soft belt and pickups is a lot comfier than some of the previous HRMs I’ve used before.

image

image

UPDATE:
From the logs it appears people are interested in where to buy these in the UK. Mine came from these guys, http://www.heartratemonitor-app.com/zephyr_hxm_bluetooth_heartrate_belt.html

Android Notification, Uploading Progressbar

While working on Tracks2Miles and Tracks2TitanXT I have been looking for a better way to show the status of the GPS track upload. In Tracks2Miles I have an entry in the Notification Area that changes as it moves through the steps of creating the route, uploading the track and finally adding a workout that uses the route. The first and the last steps are pretty quick HTTP post actions which return almost instantly, the uploading of the GPS track can take a long time for a big file on a slow network link and there was no way to know how much of the file had been uploaded. For Tracks2TitanXT I’m just using a AsyncTask for now which shows a dialog with a spinning progress bar.

I decided I wanted to add a progress bar to notification entry so went looking to see if anybody had outlined how to do it already. While I found this on United Coders which explained how to put a progress bar into the notification it did not show how to get the current bytes transferred data from the HTTPClient code included in Android.

I started to have a bit of a look at the HTTPClient API to see how I could get some status information out. A basic file upload looks a bit like this

final HttpResponse resp;
final HttpClient httpClient = new DefaultHttpClient();
final HttpPost post = new HttpPost(UPLOAD_URL);
ParcelFileDescriptor fileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
InputStream in = context.getContentResolver().openInputStream(uri);
InputStreamEntity entity = new InputStreamEntity(in, fileDescriptor.getStatSize());
post.setEntity(entity);
resp = httpClient.execute(post);
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
...
}

Looking at the InputStreamEntity documentation showed a method called writeTo(OutputStream outputStream). Overriding this method should allow the wrapping of the OutputStream to count the amount of data written to it.

package uk.me.hardill.upload;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.http.entity.InputStreamEntity;

public class CountingInputStreamEntity extends InputStreamEntity {
	
	private UploadListener listener;
	private long length;

	public CountingInputStreamEntity(InputStream instream, long length) {
		super(instream, length);
		this.length = length;
	}
	
	public void setUploadListener(UploadListener listener) {
		this.listener = listener;
	}
	
	@Override
	public void writeTo(OutputStream outstream) throws IOException {
		super.writeTo(new CountingOutputStream(outstream));
	}
	
	class CountingOutputStream extends OutputStream {
		private long counter = 0l;
		private OutputStream outputStream;
		
		public CountingOutputStream(OutputStream outputStream) {
			this.outputStream = outputStream;
		}

		@Override
		public void write(int oneByte) throws IOException {
			this.outputStream.write(oneByte);
			counter++;
			if (listener != null) {
				int percent = (int) ((counter * 100)/ length);
				listener.onChange(percent);
			}
		}		
	}
	
	public interface UploadListener {
		public void onChange(int percent);
	}

}

Using a Listener model allows an external class to be notified when the % uploaded changes. With a minor update to the original code we get this

final HttpResponse resp;
final HttpClient httpClient = new DefaultHttpClient();
final HttpPost post = new HttpPost(UPLOAD_URL);
ParcelFileDescriptor fileDescriptor = context.getContentResolver().openFileDescriptor(uri, "r");
InputStream in = context.getContentResolver().openInputStream(uri);
CountingInputStreamEntity entity = new CountingInputStreamEntity(in, fileDescriptor.getStatSize());
entity.setListener(this);
post.setEntity(entity);
resp = httpClient.execute(post);
if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
...
}

where the containing class has a onChange(int percent) method like this

@Override
public void onChange(int percent) {
	if(percent > lastPercent) {
		notification.contentView.setProgressBar(R.id.progressBar1, 100, percent, false);
		notificationManager.notify(1, notification);
		lastPercent = percent;
	}
}

Using a background thread started by a service to control the upload we end up with something the looks a but like this. A full example project is available here NotificationProgressTest.

Updated versions of both Tracks2Miles and Tracks2TitanXT should be available at the weekend with this new status notifications.

Tracks2TitanXT

About a month ago I was approached by Erik Morse from TitanXT to ask if I would be prepared to do something similar to Tracks2Miles for his site. At the time he did not have an API available, I said if he could run some thing up I would be prepared to have a look. Last week he sent me the details so I spent some of the long weekend running up a first pass of an app.

So Tracks2Miles now has a sister app supporting the TitanXT site called Tracks2TitanXT.

It works in much the same way as Tracks2Miles in that it hooks into My Tracks through the “Share with Friends…” option, except as well as supporting GPX files TitanXT supports the uploading of TCX files which also contain heart rate information if you are using one of the Bluetooth heart rate monitors that My Tracks supports.

The first pass is in the Android Market, it needs a few more bits of error handling and some cosmetic changes but I thought I’d let those that want to have play.

https://market.android.com/details?id=uk.me.hardill.titanxt

Tracks2Miles Facebook logon

Ever since Tracks2Miles shipped users have been having problems authorising the app if they choose to log in with their Facebook credentials.

The problem is that once the user had logged into Facebook it would redirect to a blank white page.

Last night I had another look at what was causing it.

To start with I added a Log statement to the shouldOverrideUrlLoading() method to print out the URL that was being loaded. This implied that the last URL loaded was from Facebook:

http://www.facebook.com/connect/uiserver.php?method=permissions.request&app_id=xxxxxxxxxx&display=touch&redirect_uri=https%3A%2F%2Fapi.dailymile.com%2Flogin%2Ffacebook%2Fcallback&state=next%3D%252Foauth%252Fauthorize%253Fresponse_type%253Dtoken%2526client_id%253Dxxxxxxxxxxxxxxxxxx%2526redirect_uri%253Ddm%253A%252F%252Flocalhost%252Ffoo&type=web_server&fbconnect=1&perms=email%2Cpublish_stream%2Coffline_access&from_login=1&refsrc=http%3A%2F%2Fm.facebook.com%2Fsetup_machine_mobile.php&refid=0&m_sess=MUm3C-eKFY7K8h&_rdr

I poked around at this for a while, but didn’t get very far, until Chris Banes pointed me at the source for the facebook-android-sdk, specifically the FbDialog.

When I added some trace to the onPageStarted() method I made some progress, the output from this implied that Facebook page had actually loaded successfully and redirected back to dailymile.

https://www.dailymile.com/login/facebook/callback?code=HphJjEM9nKsSez0ZW28W-FcvN80xR049KtQtk7CrykM.eyJpdiI6ImxGNVEyQ0FuSlF1X0xKdWJoU1MtZncifQ.yaVPEGNBOBPMQtZjrE431mw6a4-6yXUrvz0XrCd2ub44KKArQXpfiydYvhocYZuV0FW9mIO_3KLjBEO1XejL-EoplURcmbpoA3ueXjQJmvsu9Gf0Vaj7CLOdLOOpFw-d&state=next%3D%252Foauth%252Fauthorize%253Fresponse_type%253Dtoken%2526client_id%253Dxxxxxxxxxxxxxxxxxxxxxxxx%2526redirect_uri%253Ddm%253A%252F%252Flocalhost%252Ffoo

I had tried loading this new URL with Firefox on the desktop and immediately got a certificate mismatch error. The URL was hosted on www.dailymile.com but the cert was for api.dailymile.com

I was a little surprised that default WebView just swallowed this with no error messages, but a bit of googling and found the following blog post about how to work round the certificate miss match and even how to make it work with Android builds before 2.2

I also pointed the problem out to Ben from dailymile and he has fixed the cert mismatch with in a couple of hours.

There will be an updated version of Tracks2Miles in the next few days with these changes (just to be safe) and a couple of other updates around distance units.

WIFI presence detection

Back in my very first post I talked about using Bluetooth to detect my presence at home in order to disable the CCTV system and control a few other things.

While this works well it does not scale well to multiple people as the Bluetooth layer 2 ping takes about 5 seconds to time out if the device in not in range. This means that at most 12 different phones can be checked in a minute.

A couple of recent chats with a few people at work (Vaibhavi Joshi & Dale Lane and Bharat Bedi) got me thinking about this again. Modern phones tend to have WIFI as well as Bluetooth and 3G radios these days so I thought that I’d have a look at seeing if this could be used to locate devices.

After bit of a poke around it looked like a package called Kisment should be able to do what I wanted.

Kismet

Kismet is a client server application, the backend server reads from the network card and decodes the packets and the UI which requests data from the server over a socket connection. This also means the backend can be on a different machine, in fact several different drone backends can be consolidated in a single master backend server and all the captured data presented to UI. This means you could distribute a number of drones over site and generate a map as devices move between areas covered by the different backends.

The default client is a ncurses based application that can list all the visible networks and a chart showing the incoming packet rates. It’s great for getting a view of what networks are active which can be very useful when you have to set up a new one and want to see which channels are free.

Rather than use the default client I decided to write my own to drive the backend the way I wanted it and to make exposing the data easier (I’m going to publish detected devices on a MQTT topic). But first I had a bit of a play using the netcat (nc) command. Netcat basically pipes stdin/stdout to and from a given socket, this is useful because the Kisment protocol is just a set of simple text commands. For example the following command will get the kismet backend to return a list of all the clients it has seen to date.


echo -e '!0 enable client MAC,manuf,signal_dbm,signal_rssi' | nc localhost 2501


Returns something that looks like this:

...
*CLIENT: 00:25:69:7D:53:D9 [0x01]SagemCommu[0x01] -71 0
...

The only tricky bit about the response is that any field that can contain a space is wrapped in characters with a value of 0x01, in this case the manufacture field could contain spaces so we need the following regexp to chop up the responses for each time a client is spotted.

I decided my client in Java (because the MQTT libraries are easy to use) so I chose to use a regular expression to split up the response

Pattern.compile("\*CLIENT: ([0-9A-F:]*) \x01(.*)\x01 (-?\d+) (\d) ");

By default Kismet cycles round all the available channels to try and get a full picture of all the WIFI traffic in range, but this means it can miss some packets and in turn miss clients that are not generating a lot of traffic. To help get round this I have locked Kismet to just listen on the same channel as my WIFI access point since all my devices are likely to try and connect to it as soon as it comes in range and there is less chance of me missing detecting my phone up front.

!1  HOPSOURCE cab63dc8-9916-11e0-b51a-0f04751ce201 LOCK 13

cab63dc8-9916-11e0-b51a-0f04751ce201 is the UUID assigned to the wifi card by kismet and the 13 is the channel I run my WIFI access point on. You can find the UUID by running the following command:

echo -e '!1234 enable source type,username,channel,uuid' | nc localhost 2501

Which returns a string that looks like this every time the back end hops to new channel.

*KISMET: 0.0.0 1308611701 [0x01]Kismet_2009[0x01] [0x01]alert[0x01] 0 
*PROTOCOLS: KISMET,ERROR,ACK,PROTOCOLS,CAPABILITY,TERMINATE,TIME,PACKET,STATUS, 
PLUGIN,SOURCE,ALERT,WEPKEY,STRING,GPS,BSSID,SSID,CLIENT,BSSIDSRC,CLISRC, 
NETTAG,CLITAG,REMOVE,CHANNEL,SPECTRUM,INFO,BATTERY 
*SOURCE: orinoco_cs test 3 30b9b5a4-9b93-11e0-acfe-ee054e2c7201 
*ACK: 1234 [0x01]OK[0x01]

Publishing the last seen time on the following topic /WIFIWatch/<mac> allows applications to register to see a specific device and also build up a list of all devices ever seen and when.

WIFI Watch topics

It’s not just phones that have WIFI adapters these days, net books, tablets even digital cameras (with things like eyefi) all have , also with multiple kismet nodes it might be possible to track devices as they move around an area.

Next is to look at the signal strength information to see if I can judge a relative distance from the detection adapter.

Resources:

Kismet

Tonight I will mainly be falling off my bike

I got home this evening to find a box waiting by the door.

The box contained my first set of cycling shoes and cleat pedals.

Tonight I will mainly be falling off my bike

I wasn’t sure exactly what I wanted here so I basically picked the cheapest bits on wiggle.co.uk, but a bit of a chat with a few folk (Karl Roche) suggested I’d not done too bad.

I’ve gone for a set of Wellgo WPD982 SPD Pedals. Welgo seam to make pedals for a some of the more well known names and sell them under their own name cheaper than the others. I went for a half and half flat and cleat pedal so I can still use my bike without the shoes.

As for the shoes I got some dhb M1 MTB. There was a road version of these for the same price, but as far as I can tell the only real difference is that the mountain bike version have extra rubber bits on the sole that mean the cleat doesn’t touch the ground, which seamed like a good idea for my first set.

A couple of laps round the local housing estate this evening and I think I’ve got the hang of clipping in and more importantly unclipping before falling over when stopping, but it’s going to take a bit more practice before I head out on roads with any real traffic.

Tracks2Mile 1.1.4 – With automatic details import

After discovering that my patch for My Tracks had been pulled just before their last release (1.1.5) I’ve been looking for another way to get the information about time and distance.

After another closer look at the instructions 3rd party use instruction on the wiki and it’s possible to access the My Tracks database directly. Running a query that filters on the workout title, which I can get from the GPX files name, I can get hold of all the information. It is possible to have multiple workouts with the same name so I’m picking the last one added to the db since this has to be the most likely one you’ll be wanting to upload.

Since I’m reading direct from the database there is also the problem that if the My Tracks guys change the table layout then I could have a problem. The API provides a method that returns a Track object which holds the data but you can only use this if you know workout id, but this available at the moment.

I’ll probably stick a new patch in for My Tracks to pass the workout id so I don’t have to make this assumption, but it should be good enough for now.

Other fixes include:

  • One to stop caching photos in memory before writing them to the sd card to prevent OutOfMemoryErrors
  • Closed a couple of windows where the database was accessed after it’s been closed.

Grab it from the Android Market here

My Tracks patch pulled

So it looks like my patch to My Tracks to get it to expose the extra information needed for Tracks2Miles got pulled just before the last release because it broke the export to GMail (and dropbox).

It’s a shame it got spotted so close to the release of My Tracks 1.1.5 I didn’t get chance to look at before it went out.

It looks like Android resolves and unpacks all the Parcellable extras upfront even if they are not used by the receiving Activity or Service. So apps not expecting the Track object I was using fail with ClassNotFoundException because it’s not available.

I’ll try and find some time to come up with a new solution as soon as I get some time to think about it properly.

Tracks2Miles 1.1.0

The latest Tracks2Miles update

Added a timeline view to see what you friends have been up to.

*** Edit ***

I’ve just noticed that on some phones that after the update the launch icon will still open the Activity for publishing a new workout rather than the Timeline Activity. This is a “feature” of some of the launchers, you may need to restart your phone to get it to see the update.

*** Edit ***

Fixed up a couple of race condition type problems.

Updated the code to import from My Tracks to use the patch that has been accepted for the next release.