2008-04-07

Sleeptracker - gadget for sleep optimizers



In last month I get new gadget- Sleeptracker Pro alarm watch.
Short description how it works from original website:


SLEEPTRACKER® continuously monitors signals from your body that indicate whether you are asleep or awake. Because you wear SLEEPTRACKER® on your wrist like a watch, its internal sensors can detect even the most subtle physical signals from your body. SLEEPTRACKER® finds your best waking moments, so that waking up has never been easier.


Manufacturer created positive buzz amongst community. I have read so many positive reviews that even price tag (about 180$ in US for Pro model) doesn't stopped me out of buying it.

Some remarks about alarm clock features:
- clock with date on quite big display
- one alarm time
- sound and/or vibration alarm (sound and vibration may be too silent for very hard sleepers!)
- back light is nice
- can be worn as casual watch, but can be too bulky for some people

Because it's not normal alarm clock there are additional outcomes:
1) It wakes you in the moment (within set time window) you are better prepared to wake up, so you feel better
It generally "feels" true or it's hard to say without comparing statistics with and without Sleeptracker

2) It is shortening your sleeping time by about 15-30 minutes (it depends on sleep schedule) without negative consequences.
It's strong dependable on sleeping schedule and works best for unoptimized sleep with waking time in the middle of sleep cycle. On the other way every day sleep patterns may vary a little so monitoring device it's catching actual cycles. For me alarm clock sets up between 0 and 40 minutes before usual waking time.

3) It records R.E.M. activity during night, so data can be collected and analyzed to improve sleep habits.
Sleep data can be reviewed on watch or Sleeptracker Pro has USB port to transfer data to computer.




There are important rules I figured out that should be considered before buying that stuff:
- Sleeptracker will not work for you if you don't have enough sleep or have heavy sleep disorders
- alarm sound is silent so get enough of sleep to be ready top wake up in the morning
- it did not worked for my polyphasic sleep schedule (look at get enough sleep point)
- watch is worn on wrist, so if you place your arm under pillow or in other position that could block arm movement, Sleeptracker won't record R.E.M. phase due to lack of movements
- it may won't work for people who don't move their arms at during R.E.M. cycle (it's hard to check but it's possible)
- have I told that you should get enough sleep?

Sleeptracker Pro package contains USB cable, printed manual and little CD with software for windows. Interesting solution is used for connecting USB cable to watch. Cable ends with clip that have 3 springing pins matching connector on the backside of watch. I didn't mentioned the watch is waterproof!.

Sleeptracker software is used for transfer sleep data from watch and tracking that data with a day events like drinking coffee or alcohol, sleeping light and temperature conditions etc. I tried to run that software under WINE on Linux, but USB data transfer did not work.

So I tried to find another solution. I found the PERL script to get data from USB cable on sleeptracker forum. I found two version of script with bugs or unimplemented features so I integrated both to get one better. Instead of desktop software it can store data as text or xml files. The next nice feature of script is export to web version of Sleeptracker software at http://www.sleeptracker.net/. I'm still collecting data so later I report my findings.


Below is mentioned PERL script:

#!/usr/bin/perl -w

# This program downloads records from your Sleeptracker Pro
# and displays them as text, xml, or csv
#
# Sleeptracker and Sleeptracker Pro are trademarks of
#
# Innovative Sleep Solutions
# 2870 Peachtree Road #140
# Atlanta, GA 30305
#
# This program is NOT developed or supported by Innovative Sleep Solutions
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# You can purchase your Sleeptracker or Sleeptracker Pro from:
#
# http://www.sleeptracker.com
# http://www.sleeptracker.de
# http://www.sleeptracker.fr
# ... and some other stores
#

# Chagelog:
# --------------
# 09.12.2007: fixed bug in xml output tag
# 10.12.2007: fixed wrong cecksum calculation
# 11.12.2007: added browser output
# 13.12.2007: fixed seconds from DataA
# 14.12.2007: fixex wrong eff.alarm time, when no alert in window
#
#
#


use Device::SerialPort;
use Time::Local;
use strict;


my $browser="firefox"; # which browser to call
my $uploadURL="http://www.sleeptracker.net/import.php"; # which upload URL to call

my $numArgs = $#ARGV + 1;
my $ttyPath="";
my $format="browser"; #set default

if($numArgs > 1){
$format=$ARGV[0];
$ttyPath=$ARGV[1];
} elsif ($numArgs == 1){
$ttyPath=$ARGV[0];
} else {
help();
exit 1;
}

if (not -w $ttyPath) {
print STDERR "Can't access Sleeptracker at device '$ttyPath'\n";
exit 1;
}

print STDERR "Reading Sleeptracker data from $ttyPath\n\n";

my $serial = Device::SerialPort->new("$ttyPath");
$serial->baudrate(2400);
$serial->databits(8);
$serial->purge_all();
$serial->rts_active(0);
$serial->dtr_active(1);
# Send request
$serial->write("V");
# Wait one second
select(undef, undef, undef, 1);
# Read response
my($count, $data) = $serial->read(250); # goog for more than 70 awake moments

if($count<15){
print STDERR "Error while reading from Sleeptracker!\nWatch showing DATA screen?\n";
exit 1;
}

my @stBytes=();
my $cnt=0;
my $crc=0;
foreach my $byu (split (//, $data)) {
$cnt++;
# for debug
#printf "%03d: %02x = %d \n",$cnt,ord($byu),ord($byu);
push @stBytes,ord($byu);
if($cnt>1 && $cnt<$count-1){
$crc+=ord($byu);
}
}
#printf "%x=%d\n\n",$crc,$crc;
$crc=$crc%256;

# compare checksum
if($crc!=$stBytes[$count-2]){
print STDERR "Checksum Error while reading. $crc!=$stBytes[$count-2]";
exit 1;
}


# calculations and data formating

my $pos=1;

my (undef,undef,undef,$mday,$mon,$year,undef,undef,undef)=localtime();
my $jahr=$year+1900;
my $monat=$mon+1;
my $tag=$mday;

my $stTag=$stBytes[$pos+1];
my $stMonat=$stBytes[$pos+0];
my $stJahr=$jahr;

if($stMonat>$monat || ($stMonat==$monat && $stTag>$tag) ){
$stJahr=$jahr-1;
}

my $datum = sprintf "%02d.%02d.%4d",$stTag,$stMonat,$stJahr;
$pos+=2;

#$unknown=$stBytes[$pos];
$pos+=1;

my $window = sprintf "%2d",$stBytes[$pos];
$pos+=1;

my $toBed= sprintf "%02d:%02d",$stBytes[$pos+0],$stBytes[$pos+1];
my $toBedTS = timelocal(0,$stBytes[$pos+1],$stBytes[$pos],$tag,$monat-1,$jahr);
$pos+=2;

my $alarm =sprintf "%02d:%02d",$stBytes[$pos],$stBytes[$pos+1];
my $alarmTS=timelocal(0,$stBytes[$pos+1],$stBytes[$pos],$tag,$monat-1,$jahr);
$pos+=2;

my $cntData=$stBytes[$pos];
$pos+=1;

my @almostAwake=();
my @almostAwakePst=();

my $lastAwake=$toBedTS;
my $thisAwake=$lastAwake;
my $alltimes="";
for(my $i=0;$i<$cntData;$i++){
my $aaw=sprintf "%02d:%02d:%02d", $stBytes[$pos+($i*3)+0],$stBytes[$pos+($i*3)+1],$stBytes[$pos+($i*3)+2];
my $aawShort=sprintf "%02d:%02d", $stBytes[$pos+($i*3)+0],$stBytes[$pos+($i*3)+1];
$alltimes.=$aawShort.",";
push @almostAwake,$aaw;
$thisAwake = timelocal($stBytes[$pos+($i*3)+2],$stBytes[$pos+($i*3)+1],$stBytes[$pos+($i*3)+0],$tag,$monat-1,$jahr);
if($thisAwake<$lastAwake){
$thisAwake+=(24*60*60); # day has changed
}
my $slept=sprintf "%d",($thisAwake-$lastAwake)/60;
$lastAwake=$thisAwake;
push @almostAwakePst, $slept; #period sleeping time in sec
}
$pos+=($cntData*3);

if($thisAwake<$toBedTS){
$thisAwake+=(24*60*60); # day has changed
}

my $getUp=$almostAwake[@almostAwake-1];

# when the last awake moment was outside the window, the alert goes off at alarm time
if($lastAwake<$alarmTS-$window){
$getUp="$alarm:00";
}

my $dataAVal=($stBytes[$pos+1]*0xff)+$stBytes[$pos];
my $dataASec=$dataAVal%60;
#my $dataA=sprintf "%d:%2d",(($dataAVal-$dataASec)/60),$dataASec ;
#my $dataACalc=sprintf "%d:%2d",(($thisAwake-$toBedTS)/$cntData)/60,(($thisAwake-$toBedTS)/$cntData)%60;
my $dataA=sprintf "%d:%02d",(($dataAVal-$dataASec)/60),$dataASec ;
my $dataACalc=sprintf "%d:%02d",(($thisAwake-$toBedTS)/$cntData)/60,(($thisAwake-$toBedTS)/$cntData)%60;


# output Browser
if($format eq "browser"){
my $URLParam=sprintf "a=%s&w=%s&t=%s&dt=%s&da=%s",$alarm,$window,$toBed,$alltimes,$dataA;
my $callFirefox=sprintf "%s \"%s?%s\" &",$browser,$uploadURL,$URLParam;
print "\n";
print $callFirefox;
print "\n";
my $ret=system($callFirefox);
}

# output Text
if($format eq "text"){
print "Date: $datum\n";
print "To Bed: $toBed\n";
print "Alarm Time: $alarm\n";
printf "Effective Alarm Time: %s\n",$getUp;
print "Window: $window min\n";
print "Data A (Clock): $dataA min\n";
print "Data A (Calculated): $dataACalc min\n\n";

print "Awake moments ($cntData): \n";

my $aawCnt=0;
foreach my $awm (@almostAwake) {
printf " Data %2d: %s (slept: %3d min)\n",$aawCnt+1,$awm,$almostAwakePst[$aawCnt];
$aawCnt++;
}
print "\n";
}

# output CSV
if($format eq "csv"){
printf "%s;%s;%s;%s;%s;%s;%s;%s",$datum,$toBed,$alarm,$getUp,$window,$dataA,$dataACalc,$cntData;
my $aawCnt=0;
foreach my $awm (@almostAwake) {
printf ";%s",$awm;
$aawCnt++;
}
print ";\n";
}

# output XML
if($format eq "xml"){
print "\n";
print " $toBed\n";
print " $alarm\n";
printf " %s\n",$getUp;
print " $window\n";
print " $dataA\n";
print " \n";

my $aawCnt=0;
foreach my $awm (@almostAwake) {
printf " %s\n",$aawCnt+1,$awm,$almostAwakePst[$aawCnt];
$aawCnt++;
}
print "
\n";
print "
\n";
}



sub help {
print STDERR "Usage: sleeptracker [format] device\n";
print STDERR "format: browser(default), text, csv, xml\n";
}

2 comments:

Pavel Fatin said...

You may look at SleepArchiver - cross-platform data manager for Sleeptracker-series watches.

Tomasz Worona said...

There is an interesting post about Sleeptracker with lots of comments:

http://the-gadgeteer.com/2005/10/31/sleeptracker_watch/