Aus Linux-Magazin 12/2013

Webcam protokolliert auf Tumblr

© Aenbde, photocase.com

Ist Perlmeister Schilli unterwegs, weiß er gern, was daheim abgeht. Mit zwei Skripten bekommt er es hin, dass die angeschaffte Billigkamera über das Tumblr-API zyklisch Schnappschüsse auf der Micro-Blogplattform ablegt. Tierisch schick, diese Überwachung.

Wenn ich auf Reisen bin, trägt es sehr zu meiner Beruhigung bei, zu wissen, dass meine Wohnung weder durch eine Feuersbrunst noch durch eine anrückende Diebesbande bedroht ist. Um mein Sicherheitsbedürfnis nicht zum telefonischen Problem für meine Nachbarschaft zu machen, äugt seit einiger Zeit eine schwenkbare Kamera durch mein Wohnzimmerfenster hinaus auf die Skyline San Franciscos (Abbildung 1). Das gerade mal 60 US-Dollar teure Modell Foscam FI 8910W mit Wifi-Anschluss kann ich übers Internet fernsteuern und den Videostream aufs Handy holen – egal wo ich gerade bin.

Abbildung 1: Die schwenkbare Foscam-Kamera im Wohnzimmer des Perlmeisters blickt auf Downtown San Francisco.

Abbildung 1: Die schwenkbare Foscam-Kamera im Wohnzimmer des Perlmeisters blickt auf Downtown San Francisco.

Eine Menge Macken

Vor euphorischen Impulskäufen sei jedoch gewarnt, denn der billigen Foscam-Kamera haften einige nervige Macken an. Die erste: In der Dunkelheit schaltet sie jedes Mal ihren Infrarot-LED-Ring ein, wenn sie sich aufhängt und frisch bootet, was hin und wieder aus unerfindlichen Gründen vorkommt. Das Einschaltverhalten klingt im ersten Moment wie ein sinnvolles Feature, erweist sich bei der Platzierung unmittelbar vor einem spiegelnden Fenster aber als Fiasko, denn die Kamera blendet sich selbst so lange, bis jemand den Fehler bemerkt und den Infrarot-Ring ausschaltet.

Auf ein Firmware-Update, das sie von diesem “Feature” erlöst, warten Kunden bislang vergebens. “You get what you pay for”, so sagt man lakonisch in Amerika. Hinzu kommt, dass das Webinterface der Kamera wie ein Überbleibsel aus dem letzten Jahrhundert ausschaut: Der User bekommt einen ruckligen Videostream zu sehen und darf mit den Steuerknöpfen links oben den Kamerakopf etwa 180 Grad zu den Seiten und 90 Grad nach oben schwenken (Abbildung 2).

Dass der eingebaute Foscam-Server sein Passwort im Klartext per HTTP statt per HTTPS entgegennehmen will, ist ein weiterer Fauxpas, dem vernunftbegabte User bei übers Internet übertragenen Bildern mit einem VPN begegnen.

Steht die Kamera daheim und möchte man von außen darauf zugreifen, muss die Firewall des Routers mittels Portforwarding eingehende Requests weiterleiten. Da die Kamera mit einem dynamischen DNS-Dienst zusammenarbeitet, bleibt das Webinterface unabhängig von der dynamisch vergebenen WAN-IP stets unter der gleichen URL erreichbar, etwa »http://XXX.myfoscam.org:5148« .

Abbildung 2: Das funktionsarme und optisch altbackene Webinterface der Foscam-Kamera.

Abbildung 2: Das funktionsarme und optisch altbackene Webinterface der Foscam-Kamera.

Online PLUS

In einem Screencast demonstriert Michael Schilli das Beispiel: https://www.linux-magazin.de/plus/2013/12

Der Plan: Bloggen auf Kommando

Da ich aber nun mal die Kamera besitze, versuche ich das Beste draus zu machen. In erster Linie erscheint es mir sinnvoll, statt mich hin und wieder übers Internet in die Kamera einzuwählen und nach dem Rechten zu sehen, dass ich regelmäßig Schnappschüsse von der Kamera ziehe und ins Internet stelle. Die Standbilder kann ein Skript dann auf einer Webseite aufreihen – und ein Blick genügt, um den Tagesablauf zu kontrollieren. Genau das ist mein Plan für diesen Perl-Snapshot.

Passend dazu fiel mir neulich auf, dass die Micro-Blogplattform Tumblr, die mein Arbeitgeber Yahoo vor etwa einem halben Jahr geschluckt hat, ein programmierbares API anbietet. Ein Blick ins CPAN offenbarte, dass ein eifriger Open-Source-Programmierer mit WWW::Tumblr bereits ein entsprechendes Perl-Modul veröffentlicht hat. Der Rest war Formsache: Ein Cronjob ruft das später in Listing 2 vorgestellte Skript mehrmals am Tag auf und holt einen aktuellen Schnappschuss von der Kamera ab.

Das Bild schickt das Skript dann per API an das Tumblr-Blog, das die Meldungen chronologisch darstellt und allerhand sozialen Plattformschnickschnack wie Like-Knöpfe oder eine Reblog-Funktion anbietet (Abbildung 3). Da die meisten Tumblr-User mehrere Blogs verfolgen, bietet es sich an, den heimisch produzierten Bilderreigen in die Reihe interessierender Blogs aufzunehmen und neben anderen Postings zu konsumieren (Abbildung 4).

Abbildung 3: Bei jedem Aufruf des Skripts »tumblr-post« taucht im Tumblr-Blog ein Standbild der Kamera auf.

Abbildung 3: Bei jedem Aufruf des Skripts »tumblr-post« taucht im Tumblr-Blog ein Standbild der Kamera auf.

Abbildung 4: Nachdem das Blog in die Folgeliste aufgenommen ist, platzieren sich seine Postings zwischen andere Publikationen.

Abbildung 4: Nachdem das Blog in die Folgeliste aufgenommen ist, platzieren sich seine Postings zwischen andere Publikationen.

Oauth gewährt Zugang zum Tumblr-Blog

Damit das Perl-Skript »tumblr-post« nachher automatisch auf das Blog eines Users schreibend zugreifen darf, muss Tumblr es als Applikation registriert haben. Zudem ist es nötig, dass der User der Applikation entsprechende Rechte einräumt. Die Schritte dorthin beschreibt [3].

Abbildung 5 zeigt die Registrierung der Testapplikation »Perlsnapshot« ; da es sich um ein Skript und nicht um eine App fürs iPhone oder ein Android-Gerät handelt, lasse ich die Felder »App Store URL« und »Google Play Store URL« leer. Als »Default Callback URL« , also die Webadresse, die Tumblr nach der Autorisierung seitens des Users mit den generierten Access-Tokens aufruft, ist »http://localhost:8082« eingetragen (Abbildung 6).

Als Applikations-Icon habe ich einfach ein 128 mal 128 Pixel großes Selbstporträt hochgeladen. Das später aufgerufene Skript in Listing 1 zum Einholen der Genehmigung des Users und zum Einsammeln der Zugriffsschlüssel startet nämlich einen Webserver auf dem heimischen Linux-Rechner.

Nach einem Klick auf »Register« unter dem ausgefüllten Formular präsentiert Tumblr einen Consumer Key und einen Secret Key (Abbildung 7). Diese beiden Hex-Strings identifizieren eine registrierte Tumblr-Applikation, die wiederum bei Usern um Zugriffsrechte buhlen darf.

Abbildung 5: Nach Registrieren der Applikation …

Abbildung 5: Nach Registrieren der Applikation …

Abbildung 6: … unter Angabe der Callback-URL …

Abbildung 6: … unter Angabe der Callback-URL …

Abbildung 7: … erzeugt die Tumblr-API-Seite bereitwillig den Oauth-Token.

Abbildung 7: … erzeugt die Tumblr-API-Seite bereitwillig den Oauth-Token.

Alleskönner Mojo

Wie schon in früheren Perl-Snapshots mit Oauth-kontrollierten Applikationen wie Google Drive [4] holt auch Listing 1 per Mojolicious-Modul vom CPAN die Erlaubnis zum Publizieren von Blogeinträgen ein. Beim Start per »./tumblr-oauth« fährt es entsprechend der Meldung

[Sat Oct 12 09:56:27 2013] [info]
Listening at "http://localhost:8082".
Server available at http://localhost:8082.

auf Localhost und auf Port 8082 einen Webserver hoch, der, falls ein Browser die URL »http://localhost:8082« anfragt, diesem nur einen Link mit dem Text “Login on Tumblr” zuschickt. Klickt der User darauf, landet er auf Tumblrs Login-Seite, wo er sich mit E-Mail-Adresse und Passwort identifizieren soll, falls er nicht sowieso schon eingeloggt war.

Tumblr zeigt dann den Dialog in Abbildung 8 an, um vom User für die Applikation »Perlsnapshot« die Erlaubnis einzuholen, lesend wie schreibend auf dessen Blog zuzugreifen. Das vorher von mir zu Testzwecken eingerichtete Blog “Schtonk’s Rants” unter http://schtonk.tumblr.com soll später die Kamerabilder darstellen. Klickt der User auf »Allow« , verweist Tumblr den Browser zurück auf die vorher eingestellte Callback-URL (»http://localhost:8082« ) und schiebt dem Server dort mit »oauth_token« und »oauth_verifier« zwei weitere Zugriffstokens unter.

Mit diesen darf der Empfänger den gewährten Rechten entsprechend auf dem Blog des Users herumorgeln, beinahe so, als wäre er selbst dort eingeloggt. Allerdings musste der User der Applikation kein Passwort mitteilen, sondern nur einen Token, den er zudem jederzeit widerrufen kann.

Abbildung 8: Der User autorisiert das Skript zum Posten von neuen Tumblr-Artikeln.

Abbildung 8: Der User autorisiert das Skript zum Posten von neuen Tumblr-Artikeln.

Listing 1

tumblr-oauth

01 #!/usr/local/bin/perl -w
02 use strict;
03 use Storable;
04 use WWW::Tumblr::Authentication::OAuth;
05 use Mojolicious::Lite;
06 use YAML qw( DumpFile );
07 use Sysadm::Install qw( :all );
08
09 my( $home ) = glob "~";
10 my $cfg_file     = "$home/.tumblr.yml";
11 my $local_url    = "http://localhost:8082";
12 my $consumer_key = "
  
   XXX
  ";
13 my $secret_key   = "
  
   YYY
  ";
14
15 my $tumblr_oauth =
16    WWW::Tumblr::Authentication::OAuth->new(
17   consumer_key => $consumer_key,
18   secret_key   => $secret_key,
19   callback     => "$local_url/callback",
20 )->oauth_tools;
21
22 @ARGV = (qw(daemon --listen), $local_url);
23
24 ###########################################
25 get '/' => sub {
26 ###########################################
27   my( $self ) = @_;
28
29   $self->stash->{login_url} =
30     $tumblr_oauth->authorize_url();
31
32 } => 'index';
33
34 ###########################################
35 get '/callback' => sub {
36 ###########################################
37   my ( $self ) = @_;
38
39   my $oauth_token    =
40     $self->param( "oauth_token" );
41   my $oauth_verifier =
42     $self->param( "oauth_verifier" );
43
44   $tumblr_oauth->oauth_token(
45       $oauth_token );
46   $tumblr_oauth->oauth_verifier(
47       $oauth_verifier );
48
49   DumpFile( $cfg_file, {
50     oauth_token    => $oauth_token,
51     oauth_verifier => $oauth_verifier,
52     consumer_key   => $consumer_key,
53     secret_key     => $secret_key,
54     token => $tumblr_oauth->token(),
55     token_secret =>
56       $tumblr_oauth->token_secret(),
57   } );
58
59   $self->render(
60     text => "Tokens saved in $cfg_file.",
61             layout => 'default' );
62 };
63
64 app->start();
65
66 __DATA__
67 ###########################################
68 @@ index.html.ep
69 % layout 'default';
70 <a href="http://<%=%20$login_url%20%>"
71 >Login on Tumblr</a>
72
73 @@ layouts/default.html.ep
74 <!doctype html><html>
75   <head><title>Token Fetcher</title></head>
76     <body>
77       <pre>
78       <%== content %>
79       </pre>
80     </body>
81 </html>

Ein lokaler Webserver

Listing 1 zieht hierzu das CPAN-Modul »WWW::Tumblr::Authentication::OAuth« herein, das die zum Abholen der Tokens notwendigen URLs bereits enthält. In den Zeilen 12 und 13 stehen in den Variablen »$consumer_key« und »$secret_key« die in Abbildung 7 beim Registrieren der Applikation erhaltenen Werte.

Damit das Modul Mojolicious::Lite den Webserver startet, erwartet es einige Optionen auf der Kommandozeile. Entgegen allen Erwartungen startet die Option »daemon« den Webserver im Vordergrund und »–listen« bekommt die in Zeile 11 gesetzte URL. Damit »tumblr-oauth« ohne Kommandozeilen-Parameter auskommt, stopft Zeile 22 die Optionen kurzerhand in den Array »@ARGV« und schiebt sie so dem Mojolicious-Modul unter.

Browseranfragen auf Port 8082 ohne Pfadangabe landen beim Code ab Zeile 25, der die Stash-Variable »login_url« setzt und dann damit das Template im »DATA« -Bereich des Skripts ab Zeile 68 in eine HTML-Seite mit einem Login-Link umwandelt und den Browser darstellen lässt. Verzweigt Tumblr nach dem Einholen der Erlaubnis beim User zurück zum Mojolicious-Server, geschieht dies unter dem Pfad »/callback« und der Code ab Zeile 35 kommt zur Ausführung.

Zeile 49 legt mit »DumpFile()« aus dem CPAN-Modul YAML alle vier erhaltenen Tokens sowie zwei neue mit »token()« beziehungsweise »token_secret()« erzeugte Accesstokens im lesbaren Yaml-Format in der Datei ».tumblr.yml« im Homeverzeichnis ab. Später greifen Applikationsskripte auf die Datei zu, lesen die Tokens aus und erhalten dadurch Zugang zum Blog des Users.

Schüsse aus dem Fenster

Listing 2 zeigt die eigentliche Anwendung, die Fotos von der Überwachungskamera abholt. Ab Zeile 13 muss der Benutzer die Webadresse seiner eignen Kamera einsetzen, dazu den Usernamen und das Passwort für die Weboberfläche der Kamera. Die Methode »credentials()« des Objekts vom Typ WWW::Mechanize speichert diese Information und fügt sie bei Webanfragen automatisch bei, sobald der Kamera-Webserver nach einem Passwort fragt. Eigentlich genügt zum Einholen von Daten auf einem Webserver das Perl-Modul LWP::UserAgent, aber die Superklasse WWW::Mechanize bietet eine bequemere »credential()« -Methode an, die weniger Parameter erfordert.

Die Foscom-Kamera liefert unter dem Pfad »/snapshot.cgi« einen Schnappschuss ihres Blickfelds, die Funktion »blurt()« aus dem CPAN-Modul Sysadm::Install schreibt die Bilddaten in Zeile 22 in eine lokale Datei namens »snapshot.jpg« .

Listing 2

tumblr-post

01 #!/usr/local/bin/perl -w
02 use strict;
03 use Sysadm::Install qw(:all);
04 use YAML qw( LoadFile );
05 use WWW::Tumblr;
06 use WWW::Mechanize;
07
08 my( $home )  = glob "~";
09 my $cfg_file = "$home/.tumblr.yml";
10
11 my $ua = WWW::Mechanize->new();
12 my $picfile = "snapshot.jpg";
13 my $url = "http://
  
   XXX.myfoscam.org
  " .
14   ":5148/snapshot.cgi";
15 my $site = "
  
   schtonk
  .tumblr.com";
16 my $cam_user = "
  
   XXX
  ";
17 my $cam_pass = "
  
   YYY
  ";
18
19 $ua->credentials( $cam_user, $cam_pass );
20
21 my $resp = $ua->get( $url );
22 blurt $resp->content(), $picfile;
23
24 my $cfg = LoadFile( $cfg_file );
25
26 my $t = WWW::Tumblr->new(
27   consumer_key => $cfg->{ consumer_key },
28   secret_key   => $cfg->{ secret_key },
29   token        => $cfg->{ token },
30   token_secret => $cfg->{ token_secret },
31 );
32
33 my $blog = $t->blog( $site );
34
35 my $post = $blog->post(
36   type => 'photo', data => [$picfile] ,
37 );
38
39 if( $post ) {
40    print "I have published post id: " .
41       $post->{id}, "\n";
42 } else {
43    die $blog->error;
44 }

Abschluss und Ausblick

Nun kommen die Tumblr-Funktionen zum Zuge, Zeile 24 liest die Yaml-Datei mit den Tokens ein, Zeile 26 erzeugt ein neues Objekt vom Typ WWW::Tumblr. Über das Tumblr-API holt Zeile 33 dann Informationen zum vorher definierten Testblog auf »schtonk.tumblr.com« ein und die Methode »post()« sendet den Bilddatei-Inhalt unter Angabe des Typs »photo« an den Tumblr-Server. Den Erfolgsfall signalisiert »$post« mit einem wahren Wert. Wer nun das Skript per »./tumblr-post« startet, erhält die ID des neu angelegten Blogeintrags:

I have published post id: 63791478637

Leider bietet das API keine Möglichkeit, dem Bild einen Text beizufügen. Das scheint zurzeit nur per Browserinterface zu funktionieren, das HTML-Seiten mit eingebauten Fotos erlaubt. Theoretisch könnte das Skript jedoch Texte hochladen und die Bilder von einer anderen Seite referenzieren; doch für die Überwachungsfotos ist es praktischer, wenn Tumblr die Bilder selbst speichert. Eine praktikable Variante wäre die Beschriftung im Bild selbst, wie vorigen Monat im Snapshot mit dem CPAN-Modul Imager vorgestellt. So ließen sich kurze Texte, die aktuell gemessene Außentemperatur zum Beispiel, ins Bild einpassen.

Der Autor

Michael Schilli arbeitet als Software-Engineer bei Yahoo in Sunnyvale, Kalifornien. In seiner seit 1997 laufenden Kolumne forscht er jeden Monat nach praktischen Anwendungen der Skriptsprache Perl. Unter mailto:mschilli@perlmeister.com beantwortet er gerne Fragen.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 4 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben