Ein elektronischer Armreif namens "Up" der Firma Jawbone misst Tag und Nacht die Armbewegungen seines Trägers schließt daraus auf zurückgelegte Wegstrecken und nächtliche Schlafrhythmen. Fitnessforscher dürfen die gesammelten Daten nicht nur mit den offiziellen Smartphone-Apps, sondern auch mit Perl-Skripts und mittels der inoffiziellen Web-API abgreifen.
Um der allgemeinen Tendenz zur Bürgerverfettung entgegenzuwirken, trägt man heutzutage kleine Gadgets mit sich herum, die einen daran erinnern, wie wenig man sich doch bewegt. Stundenlang nur regungslos vor dem Bildschirm zu sitzen ist ungesund, statt dessen springt der Gesundheitsapostel schon mal auf, um einmal ums Karree zu gehen oder vielleicht sogar die Toilette im vierten Stock aufsuchen, welchen man selbstverständlich nicht im Aufzug, sondern schwer schnaufend übers Treppenhaus erreicht.
Abbildung 1: Der Armreif "Jawbone", der aus den Armbewegungen auf die Aktivitäten des Trägers schließt. |
Ein elektronischer Armreif wie das Up-Band von der Firma Jawbone misst dabei die dabei gegangenen Schritte und zeigt später über die zugehörige App fürs Smartphone die zurückgelegte Wegstrecke und die verbrauchten Kalorien an. Dabei scheint das Gerät tatsächlich nur momentane Beschleunigungswerte zu messen, und diese zeitlich aufzukumulieren. Die geographische Position des Trägers ließe sich mit einem GPS-Chip ermitteln, aber der würde die kleine Batterie des Geräts wohl in kürzester Zeit leersaugen.
Auf Youtube hat ein Elektronik-Freak die äußere Gummihülle des Armbands aufgeschlitzt ([2]) und die wasserdicht eingeschweißten Komponenten ans Licht gebracht. Er fand ein halbes Dutzend kleinerer Platinchen mit SMD-Komponenten, aber außer einem Beschleunigungsmesser, der Lithium-Ion-Batterie inklusive Ladechips, einem Vibrator und Komponenten zum Andocken an den Audio-Port des Smartphones kam nichts zutage.
Abbildung 2: Das Smartphone zeigt die Daten an: Nicht genügend Schlaf, aber das Fitness-Ziel von 10.000 Schritten pro Tag wurde erreicht. |
Der Armreif schickt also lediglich die zeitlich aufgereiten Beschleunigungsdaten an ein Machine-Learning-System, das aufgrund des Bewegungsmusters errät, welche Art von Bewegung vorlag (Gehen, Laufen, Fitnesstrainer), wieviele Schrittbewegungen der Träger dabei durchführte und was wohl die dabei zurückgelegte Wegstrecke war.
Abbildung 3: Auf Youtube hat ein Bastler den Armreif aufgeschlitzt und erklärt die Komponenten. |
Wer den Reif auch nachts trägt, der kann sich am Morgen staunend seine Schlafmuster ansehen. Die App zeigt graphisch an, wann der Träger zu Bett ging, wann er eingeschlafen ist, wie oft er aufgewacht oder aufgestanden ist, und weckt ihn auf Wunsch mit sanftem Vibrieren innerhalb eines 20 Minuten langen Zeitfensters zu einem Zeitpunkt, an dem das Aufwachen am Schönsten ist. Zum Erfassen der Schlafrhythmen muss der User das Gerät allerdings vor dem Einschlafen manuell mittels eines Druckknopfs in den Schlafmodus versetzen. Bewegt sich der Träger dann lange Zeit nicht, ist er wohl tief eingeschlafen, liegen kleinere Bewegungen vor, ist er in eine leichtere Schlafphase eingetreten.
Abbildung 4: Erst um 1:30 ins Bett, dann um halb sieben kurz aufgewacht und gelesen, dann nochmal eingeschlummert und um acht aufgestanden. |
Die Batterie im Band hält ungefähr eine Woche ohne Nachladen durch, und um die Daten auszulesen, zieht der User ein Stöpselchen an einem Ende des Bandes ab, um einen Audio-Stecker freizulegen. Diesen führt er in den Audioport seines Smartphones ein (Abbildung 5), startet die "Up"-App und das Band schickt wie ein Audiokoppler vom anno dunnemals die Bewegungsdaten an die App und damit an den Server in der Jawbone-Cloud. Von dort erhält dann die App wieder die aufbereiteten Daten zurück und zeigt sie graphisch ansprechend an (Abbildungen 2 und 4). Wer will, kann Freunde in sein "Team" einladen und einen Fitnesswettbewerb organisieren. Wenn man den Arbeitskollegen nicht auf die Nase binden möchte, dass man sich nächtelang unruhig im Bett hin- und herwälzt und nicht schlafen kann, lassen sich diese eher heiklen Informationsbissen im Bereich "Sharing" von der Publikation ausnehmen.
Abbildung 5: Steckt der Audiostecker des Armbands in der Buchse des Smartphones, während die App "Up" läuft, überträgt sie die Daten. |
Nun liegen die Schritt- und Schlafdaten nicht nur über die App, sondern auch in etwas roherer Form vor. Dazu nutzt das Skript in Listing 1 das CPAN-Modul WWW::Jawbone::Up und damit indirekt eine inoffizielle Web-API, die Bewegungsdaten in Perl-Skripts importiert. So darf der experimentierfreudige Fitness-Enthusiast zum Beispiel auf der Linux-Kommandozeile schnell mal seine bisher hochgeladenen Daten abfragen:
$ ./uptest Mike Schilli walked 8.597km today Mike Schilli slept for 6h19m last night
Listing 1 zieht dazu erst das CPAN-Modul herein und loggt sich dann mit der
connect
-Methode in der Up-Cloud ein.
Die Email-Adresse und das Passwort in den Zeilen 6 und
7 sind durch den bei Up registrierten User-Account zu ersetzen, den
der User bei der Aktivierung des Bandes angelegt hat. Die Methode
user()
holt die persönlichen Daten des eingeloggten Users ein. Aus
diesen extrahiert dann name()
den registrierten Vor- und Nachnamen.
01 #!/usr/local/bin/perl -w 02 use strict; 03 use WWW::Jawbone::Up; 04 use DateTime::Duration; 05 06 my $email = 'user@isp.com'; 07 my $pass = 'changeme'; 08 09 my $up = WWW::Jawbone::Up->connect( 10 $email, $pass ); 11 12 my $user = $up->user(); 13 my $score = $up->score(); 14 15 print $user->name . ' walked ' . 16 $score->move->distance . 'km today', "\n"; 17 18 my $dtd = DateTime::Duration->new( 19 minutes => $score->sleep->asleep()/60 ); 20 21 print $user->name . " slept for ", 22 $dtd->hours(), "h", int( $dtd->minutes() ), 23 "m", " last night\n";
Die Methode score()
erhält die aufbereiteten Bewegungsdaten vom
Up-Server. Die in den letzten 24 Stunden vom Träger zurückgelegte Wegstrecke
in Kilometern kommt mit move()->distance()
zutage. Die Schlafdauer
liefert sleep()->asleep()
in Sekunden. Die nachfolgende Zeile
teilt den Wert durch 60, erhält so Minuten, und das CPAN-Modul
DateTime::Duration errechnet daraus die vollen Stunden und
überbleibenden Minuten. Bei Sekunden stellt es sich stur, da dies
wegen Schaltsekunden in Sonderfällen fehlerhaft wäre.
Mit der Fülle der verfügbaren Daten lassen sich nun allerhand Sperenzchen anstellen. Ansprechende Diagramme erfordern lediglich ein Grafikpaket wie Chart::Clicker (erhältlich auf dem CPAN, Dokumentation auf [3]), das sie ohne viel Handarbeit aber trotzdem ästethisch vollwertig generiert. Abbildung 6 zeigt zum Beispiel zwei Graphen in einem Schaubild: die während der letzten 24 Stunden aufkumulierte Wegstrecke in Lila und die in dynamisch festgelegten Intervallen gemessenen Schritte in gelb.
Um Speicherplatz zu sparen, legt das Band Daten nämlich in unterschiedlich langen Messintervallen ab. Rührt sich lange Zeit nichts, wie zum Beispiel in der Nacht, wenn der Träger schläft, beträgt das Zeitfenster mit dem Zählwert für die registrierten Bewegungen schon mal eine Stunde oder mehr. In vollem Lauf hingegen schreibt der Armreif jede Minute einen Eintrag in den Speicher, der die Anzahl der Schritte festlegt. Der Up-Server berechnet daraus die geschätzte zurückgelegte Strecke, die durchschnittliche Geschwindigkeit, die bei der Aktivität verbrannten Kalorien und die Anzahl der Sekunden, in denen der User im Zeitintervall aktiv war.
Abbildung 6: Zurückgelegte Wegstrecke über die letzten 24 Stunden in Lila und die in dynamisch gewählten Messintervallen gezählten Schritte in Gelb. |
All diese Informationen kann ein Skript wie Listing 2 über Methoden abgreifen und mit Hilfe des Chart-Pakets grafisch darstellen. Das Paket Chart::Clicker ([3]) vom CPAN erzielt formschöne Ergebnisse und ist außerdem so flexibel, dass es sogar wie in Abbildung 6 gezeigt zwei verschiedene Arten von Graphen in ein Schaubild packen kann: Die über die Zeitachse bislang zurückgelegten Kilometer packt ein Render-Engine namens Chart::Clicker::Renderer::Area in eine ausgemalte Fläche (lila in Abbildung 6) und die Schübe mit Step-Zählwerten zeigt eine Balkengrafik mit dünnen "Bars" in rot, ebenfalls über die Zeitachse.
Von Haus aus stellt Chart::Clicker Daten in Form von X/Y-Koordinaten dar. Bestehen die X-Werte aus Datumsangaben, sorgt das Modul Chart::Clicker::Axis::DateTime dafür, dass die als Unix-Sekunden angegebenen Zeitwerte schön im Datums- oder Uhrzeitformat auf der X-Achse erscheinen.
01 #!/usr/local/bin/perl -w 02 use strict; 03 use Chart::Clicker; 04 use Chart::Clicker::Renderer::Area; 05 use Chart::Clicker::Renderer::Bar; 06 use Chart::Clicker::Axis::DateTime; 07 use Chart::Clicker::Data::DataSet; 08 use Chart::Clicker::Data::Series; 09 10 use WWW::Jawbone::Up; 11 use DateTime::Duration; 12 13 my $email = 'user@isp.com'; 14 my $pass = 'changeme'; 15 16 my $up = WWW::Jawbone::Up->connect( 17 $email, $pass ); 18 19 my @band = $up->band( ); 20 21 my @time = (); 22 my @steps = (); 23 my @distance = (); 24 my $total = 0; 25 26 for my $band ( @band ) { 27 push @time, $band->time(); 28 push @steps, $band->steps(); 29 30 $total += $band->distance(); 31 push @distance, $total; 32 } 33 34 my $cc = Chart::Clicker->new( 35 width => 1000, height => 800 ); 36 37 my $def_ctx = $cc->get_context('default'); 38 39 my $steps = 40 Chart::Clicker::Data::Series->new( 41 values => \@steps, 42 keys => \@time, 43 name => "Steps", 44 ); 45 46 my $distance = 47 Chart::Clicker::Data::Series->new( 48 values => \@distance, 49 keys => \@time, 50 name => "Distance", 51 ); 52 53 my $ds = 54 Chart::Clicker::Data::DataSet->new( 55 series => [ $distance ] ); 56 my $ds_steps = 57 Chart::Clicker::Data::DataSet->new( 58 series => [ $steps ] ); 59 60 my $steps_ctx = 61 Chart::Clicker::Context->new( 62 name => 'steps' 63 ); 64 $cc->add_to_contexts( $steps_ctx ); 65 66 $ds_steps->context( "steps" ); 67 68 $cc->add_to_datasets( $ds ); 69 $cc->add_to_datasets( $ds_steps ); 70 71 my $dtaxis = 72 Chart::Clicker::Axis::DateTime->new( 73 format => "%H:%M", 74 time_zone => "America/Los_Angeles", 75 position => "bottom", 76 orientation => "horizontal" 77 ); 78 79 $def_ctx->domain_axis( $dtaxis ); 80 $steps_ctx->domain_axis( $dtaxis ); 81 82 my $ren = 83 Chart::Clicker::Renderer::Area->new( 84 opacity => .7, 85 ); 86 $ren->brush->width( 5 ) ; 87 $def_ctx->renderer( $ren ); 88 $steps_ctx->renderer( 89 Chart::Clicker::Renderer::Bar->new( 90 opacity => .6, bar_width => 1 ) 91 ); 92 93 $cc->write_output( "chart.png" );
Das Skript holt sich in Zeile 19 die Rohdaten des Bandes während der
letzten 24 Stunden mit der Methode band()
ab. Wahlweise ließe sich
eine beliebige Zeitraum festlegen. Zurück kommt ein
Array von Einträgen, von denen jeder eine Referenz auf einen
Hash enthält, der unter den Einträgen steps
die Anzahl der pro
Zeitperiode abgespulte Schrittzahl, unter distance
die
zurückgelegte Distanz, unter speed
die Durchschnittsgeschwindigkeit
während der Messperiode. In time
steht der Zeitstempel, in active_time
der Teil des Zeitfensters in dem der User sich bewegt hat und in
calories
die Anzahl der verbrannten Kalorien.
Mit den abgeholten Werten füllt das Skript dann drei Arrays: @time
mit den Zeitstempeln im Unix-Format, @steps
mit der Schrittzahl an
diesen Zeitpunkten, und @distance
, mit der bis zum jeweiligen
Zeitpunkt zurückgelegten Gesamtstrecke.
Zeilen 40 und 47 erzeugen aus den Zeit/Step bzw. Zeit/Distanz-Kombinationen jeweils eine Datenserie vom Typ Data::Series. Ein Datensatz vom Typ Data::DataSet für einen Graph kann in Chart::Clicker mehrere Datenserien enthalten, aber die Zeilen 54 und 57 erzeugen jeweils einen Datensatz mit nur einer Serie für die beiden Graphen. Beide sollen verschieden dargestellt werden, einer als Area-Graph, und der andere als Balkengraphik, wenngleich im selben Diagramm.
Chart::Clicker arbeitet zum Rendern der Graphen in sogenannten Kontexten,
von Haus aus ist "default" eingestellt und Zeile 37 holt das zugehörige
Objekt. Zur Darstellung des zweiten Datensatzes definiert Zeile 61
einen weiteren Kontext namens steps
und Zeile 64 fügt ihn zum System hinzu.
Mit add_to_datasets()
fügen dann die Zeilen 68/69 beide Datensätze
zum Clicker-Objekt hinzu und die Methode domain_axis()
weist beiden
über den Kontext die Zeitachse Axis::DateTime zu, die die X-Werte
von Datenreihen als Datumsangaben interpretiert und ebenso darstellt.
Die Angabe %H:%M
weist den Formatierer an, vom Unix-Datum jeweils
nur die Stunde und die Minute in die Achse einzuzeichnen. Die Zeitzone
"America/Los_Angeles" gilt nur für in San Francisco und Umgebung
Ansässige, und ist entsprechend auf die lokalen Gegebenheiten anzupassen.
Der Name der Zeitzone entspricht der dem Datumsmodul zugrunde liegenden
Olson-Datenbank, und die Wikipedia-Seite auf [3] listet Werte für Europa
und den Rest der Welt auf.
Abbildung 7: Beispiele für mit Chart::Clicker erzeugte Graphen (Quelle: [3]) |
Der Zaubertrick mit den zwei verschiedenen Graph-Typen läuft nun über
den Kontext: Zeile 87 weist dem Default-Kontext den Area-Renderer zu,
während der Steps-Kontext in Zeile 88 den Bar-Renderer bekommt. Der
Parameter opacity
bestimmt in beiden Fällen
die Durchsichtigkeit des Graphen:
bei Werten um 0 ist sind die gemalten Linien und Flächen praktisch blickdicht,
um 1 herum vollkommen durchsichtig. Die grafisch aufgemotzten
Bewegungsdaten in Abbildung 6 enthüllen, dass ich nach
der Arbeit schlechten Gewisssens noch schnell zum nahegelegenen
Dolores-Park hinunter gelaufen bin, um noch einige Kilometer auf den
Armreif zu spulen, denn an einem normalen Bürotag kommt kaum jemand
auf die empfohlenen 10.000 Schritte. Während des abendlichen Lungerns
vor dem Fernseher kamen erwartungsgemäß keine Kilomenter aufs Armband,
aber nach ausgedehnter Bettruhe bis 8 Uhr morgens ging ich die
500 Meter bis zur privaten Bushaltestelle des Yahoo-Shuttles in San
Francisco. Untertags erhöhte sich die gemessene Laufstrecke gemächlich,
während der Träger in der Arbeit zwischen Meetings in unterschiedlichen
Räumen oder gar Gebäuden hin- und herlief. Auf dem Weg von der Bushaltestelle
zurück zur Wohnung gings's den Berg rauf und die Anzahl der zurückgelegten
Schritte erhöhte sich erneut, bis sie sich auf etwa 10.000 für den
Tag einfand.
Wer das Up-Band von Jawbone erwirbt, sollte sich mental darauf einstellen, dass es sich um ein noch nicht 100% ausgereiftes Produkt handelt. Die schlanke Bauweise des Armreifs beschwört erwartungsgemäß Qualitätsmängel herauf. Auf Diskussionsforen ist zu hören, dass die Armreife wohl öfter mal den Geist aufgeben, und dass dann der Kundenservice der Firma Jawbone nicht immer erwartungsgemäß reagiert. Die ersten Versionen des UP-Bands wiesen katastrophale Fehlerraten auf, neuere arbeiten zuverlässiger, aber auch heute hört man noch von Reifen, die ihre Batterie nicht richtig laden oder sich vollends aufhängen. Konkurrenz zum UP-Band ist in Form des "Fitbits" schon länger auf dem Markt. Das kleine Teil im Format eines USB-Sticks steckt man tagsüber in die Hosentasche, nachts muss man ihn aber in einem relativ breiten Stoffband am Arm festbinden.
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2013/10/Perl
"Jawbone UP Pedometer Teardown", EEVblog #412, http://www.youtube.com/watch?v=sRjHAGsl6ws
Chart Clicker, http://gphat.github.io/chart-clicker/
Zeitzonen in der Olson-Datenbank: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones