Schlagwort-Archive: Raspberry Pi

Phoniebox: Der Koffer für den kleinen Mann

Menschen mit kleineren Kindern kennen sicherlich die Toniebox: Eine kleine Kiste, auf die kleine Kinder kleine Figuren stellen, worauf die Kiste dann Musik oder Hörspiele abspielt. Für Menschen mit Spaß am Basteln gibt es dazu ein alternatives Selbstbauprojekt, die sog. Phoniebox. Mein Freund Markus hat ein kleines Kind und Spaß am Basteln. Ich habe auch Spaß am basteln, also haben wir gebastelt. Das ist dabei herausgekommen:

Phoniebox kann sowohl lokal auf der Kiste gespeicherte Audiodateien abspielen, als auch Spotify (einzelne Songs, Playlisten, Alben, was auch immer). Hat die Box kein WLAN, dann spielt sie eben nur die lokalen Sachen ab, denn Spotify kann nur gestreamt werden.

Was jetzt noch kommt ist mehr eine Gedankensammlung und Dokumentation dessen, was wir gemacht haben als eine Anleitung, wie man den Koffer exakt nachbaut. Der eine oder andere brauchbare Hinweis ist aber vielleicht trotzdem dabei, und das meiste ist auf den ebenfalls verlinken Projektseiten ja bestens beschrieben.

Weiterlesen

Arduino-Bastelei: Die smarte(re) Waschmaschine (Update)

Es gibt ein Update zum meinem Waschmaschinenprojekt. Zur Erinnerung: Es ging darum, bei einer recht alten Waschmaschine eine Benachrichtigung am Handy zu bekommen, sobald der Waschvorgang beendet ist.

Die Spielerei hat anfangs recht gut funktioniert, im Laufe der Zeit jedoch immer schlechter. Meine Erklärung: Der Vibrationssensor hat der Belastung nicht standgehalten. Der erste Sensor ging wirklich kaputt, ein zweiter wurde auch laufend schlechter. Schlechter bedeutet, dass die Werte immer mehr streuten und daher das zeitliche Vibrationsprofil, über das der letzte Schleudervorgang und damit das Ende des Waschvorgangs detektiert wurde, immer verrauschter und uneindeutiger wurde. Es gab Fehlalarme.

3-Achsen-Beschleunigungssensor GY-61

Über ein anderes Bastelprojekt bin ich dann auf einen einfachen 3-Achsen-Beschleunigungssensor gestoßen, den GY-61. Der gibt an drei analogen Ausgängen einfach die Beschleunigung für drei orthogonale Achsen (x, y, z) aus. Im Prinzip so ein Teil, welches heute in jedem Smartphone z.B. die Bildschirmorientierung steuert. Gravitation ist ja auch nichts anderes als eine Beschleunigung; dreht man das Handy, dann wirkt diese Beschleunigung (zumindest anteilig) in eine andere Richtung.

Ich habe nun den alten Vibrationssensor durch den neuen Beschleunigungssensor ersetzt. Von den drei Achsen kann ich allerdings nur ein einzige nutzen, weil der Wemos D1 mini nur einen analogen Eingang bietet. Hier ein paar Bilder vom Umbau:

Die Werte, die der Sensor in den drei Schleuderphasen der Waschmaschine liefert sind um Welten besser als das, was der Vibrationssensor jemals geliefert hat. Hier der Plot eines typischen Waschvorgangs:

Die Werte werden für mich zur Kontrolle an meinen Raspberry Pi geschickt und mit Hilfe der Bibliothek dygraphs geplottet. Blau: Beschleunigung. Rot: Der Schwellwert. Gelb: Dauer über dem Schwellwert. Rot: Auslösen der Benachrichtigung.

Man sieht hier schön, dass der letzte Schleudergang stärker und vor allem länger ist als die ersten beiden. Seit dem Einbau des neuen Sensors wurde damit das Ende des Waschvorgangs hundertprozentig richtig erkannt. Weiterlesen

Arduino-Bastelei: Die smarte(re) Waschmaschine

Es wäre gelogen zu sagen, dass es bei unserer Waschmaschine dringenden Optimierungsbedarf gegeben hätte. Aber als Bastler sucht man ja immer nach einer möglichst sinnvollen Kanalisation des Basteltriebs. Daher hier die im Nachhinein zusammengelogene Motivation für das aktuelle Projekt:

Unsere Waschmaschine steht im Keller. Außerdem ist sie alt, fast 18 Jahre. Damals gab es noch kein „Ich bin fertig!“-Gepiepse. Also muss man nach dem Einschalten der Maschine in etwa abschätzen, wann sie fertig sein wird und sich am besten eine Erinnerung am Handy einstellen. Sonst könnte sich eine der folgenden dramatischen Szenen abspielen:

  • Die Maschine ist fertig und niemand räumt sie aus.
  • Die Maschine ist fertig und man räumt sie viel zu spät aus.
  • Die Maschine ist fertig und man merkt es zu spät, wodurch sich die nächste Maschine verzögert, deren Ende man wieder zu spät merkt, wodurch sich die näcshte Maschine… (das Prinzip ist klar).
  • Die Maschine ist fertig und irgend etwas anderes ganz schlimmes.

Wemos D1 mini

Da hat man als Bastler jetzt also einen Wemos D1 mini herumliegen (also einem Arduino-ähnlichen Mikrocontroller mit einem ESP8266-WLAN-Modul) und fragt sich, was man – bezüglich des oben geschilderten „Problems – sinnvolles damit machen könnte. Natürlich 1) irgendwie das Ende des Waschvorgangs detektieren und dann 2) irgendwie eine Nachricht absetzen, die dann wiederum irgend jemanden zum Ausräumen der Waschmaschine animieren soll.

Weiterlesen

Who the F**K is @robodda?

robodda

Riech mal wie ich riech
hör mal wie ich stodda
ich bin einer von euch, Mensch
ich bin doch kein Robodda.

(Dendemann – O Robota)

Ich muss etwas erklären, und eigentlich ist es dafür schon fast zu spät. Am 27. Januar 2016 habe ich ein kleines Wesen in die Welt gesetzt, welches seither mein Leben bereichert. Die Rede ist von @robodda, meinen Twitter-Roboter. Dieses Dings hat schon für einige Verwirrung gesorgt, daher ist es allerhöchste Eisenbahn, etwas Klarheit zu schaffen. Das Wichtigste, was zu sagen ist: Ich bin @dasaweb und nicht @robodda! Ich schreibe nicht persönlich unter diesem @robodda-Account. Gut, verwand ist der Kleine schon mit mir, so ähnlich wie Kinder mit einem verwand sind. Aber ein Kind ist er auch nicht, er ist einfach nur ein Roboter. Präzise müsste man sagen ein „Bot“, was Wikipedia folgendermaßen definiert:

Unter einem Bot (von englisch robot „Roboter“) versteht man ein Computerprogramm, das weitgehend automatisch sich wiederholende Aufgaben abarbeitet, ohne dabei auf eine Interaktion mit einem menschlichen Benutzer angewiesen zu sein.

So sieht es aus. Der @robodda ist ein Computerprogramm, auf welches ich im laufenden Betrieb keinen Einfluss nehme, das eigenständig Tweets veröffentlicht, Nutzern folgt und entfolgt, Tweets anderer favorisiert und auf sie antwortet usw. Er verhält sich also fast wie ein normaler Twitterer. Das ist jedenfalls das hehre Ziel. Und die Verwandschaft zu mir besteht darin, dass er sich aus meinen bisher veröffentlichten Tweets bedient, sich daraus Textbausteine generiert und aus diesen Textbausteinen seine eigenen Tweets bastelt. Klar, ich leiste eine Art Erziehungsarbeit, in dem ich die Algorithmen, die sein Verhalten bestimmen, immer wieder anpasse und weiter optimiere, damit er immer mehr meinen Vorstellungen von einem guten Bot entspricht. Sonst ist er aber wirklich ein eigenständiges Wesen.

Diese Klarstellung, dass ich nicht der Bot bin, ist wirklich wichtig. Denn es kann schon mal sein, dass so ein Bot verbal Amok läuft, wie Microsoft in den letzten Wochen mit seiner Kreatur „Tay“ schmerzlich erfahren musste. Und auch mein kleiner Bot ist nicht so unschuldig wie er zunächst anmutet. Ein Beispiel:

Oder auch der hier:

Aber eigentlich ist es unfair, solche Ausrutscher als erstes zu zitieren, denn in der Regel ist das Kerlchen doch recht putzig und hier und da durchaus kreativ. Beispiele:

Manchmal wird er geradezu philosophisch:

Ich mag ihn, und ich hatte ja neulich schon mal erwähnt, dass man auch zu Dingen eine Beziehung aufbauen kann. Dazu müssen sie sich noch nicht einmal menschlich verhalten, aber wenn sie menschliche Züge haben können wir uns kaum dagegen wehren. Den @robodda wieder abzuschalten würde sich zum jetzigen Zeitpunkt ziemlich falsch anfühlen. Außer der Wind dreht und es passiert das, wovor viele irgendwie Angst haben:

Quelle: http://xkcd.com/1646/

Quelle: http://xkcd.com/1646/

„I bet it’s not too hard“. Dachte ich mir auch, nachdem ich über den Bot von @grindcrank (darf ich vorstellen, der @grindbot!) inspiriert wurde und dann den Artikel von @dasnuf über ihren @nufbot gelesen hatte. Ja, es gibt noch mehr Bots da draußen, ziemlich viele sogar. Und eine ganze Gruppe davon basieren auf dem gleichen Code, den ich schließlich auch verwendet habe. Es gibt auch andere, vermutlich intelligentere, wie den Account @deepdrumpf zum Beispiel, aber ich hatte mit @grindcrank jemanden an der Hand, bei dem ich wusste, dass er mir zur Not unter die Arme greifen kann. Mein Ziel war außerdem, das kleine Wesen auf meinem Raspberry Pi zum Leben zu erwecken, und speziell dazu habe ich kein Tutorial gefunden. Falls es dich interessiert folgt also hier eine grobe Anleitung zur Installation eines Twitter-Bots auf dem Raspberry Pi:

Weiterlesen

OAuth 2.0 – Lord, have mercy!

OAuth 2.0

Es gelingt mir nicht immer, auf dem Laufenden zu bleiben, was technische Entwicklungen im Web angeht. Vorsichtig ausgedrückt. Obwohl ich mich durchaus bemühe. Aber da draußen ist einfach zu viel los. So ging es auch an mir vorbei, dass Google angekündigt hatte, seinen Client-Login im April 2015 abschalten zu wollen. Oder ich habe einfach nicht verstanden, dass mich das betrifft. Hat es mich aber, und das gleich an verschiedenen Stellen.

Zum einen nutze ich an verschiedenen Stellen im Netz die Möglichkeit, Daten aus Google Tabellen auszulesen und diese weiter zu verarbeiten. Dieser Weg hat im Gegensatz zur Nutzung einer Datenbank den Charme, dass auch eine technisch nicht so versierte Gruppe von Usern sehr leicht Daten editieren kann, die dann direkt auf irgendwelchen Webseiten dargestellt oder für andere Dienste verarbeitet werden können.

Zum anderen brauchte ich diese Art der Authentifizierung für das Backup meiner Google Kontakte auf dem Raspberry Pi. Ich hatte darüber mal ausführlich geschrieben.

Die Nutzung des Client-Logins sah (vereinfacht) so aus, dass man sich bei Google-APIs mit seinen Google-Zugangsdaten authentifizieren konnte. Einen Schritt besser war es schon, dazu eine sog. „anwendungsspezifisches Passwort“ zu verwenden. D.h. man generierte sich bei Google ein weiteres Passwort, welches dann nur eine einzige Anwendung verwenden durfte. Vorteil: Durch Löschen des vergebenen Passworts war auch der Anwendung der Zugriff auf die Daten entzogen, außerdem musste man nicht sein richtiges Google-Passwort in irgendwelchen Skripten hinterlegen. Umgesetzt hatte ich das alles mit Hilfe des Zend Frameworks.

Diese Möglichkeit gibt es jetzt nicht mehr. OAUth 2.0 ist angesagt. OAuth ist an sich nichts neues, aber das Ding ist einfach deutlich komplexer als die herkömmliche Authentifizierung. Wie OAuth 2.0 funktioniert genau funktioniert erkläre ich hier nicht weiter, man kann das z.B. hier schön nachlesen. Ein Artikel in 5 Teilen, das sagt schon alles. Die Grundidee ist die, dass eine Anwendung einen z.B. auf eine Google-Seite weiterleitet, man sich dort authentifiziert und somit seiner Anwendung bestimmte Rechte zuweist, ohne dass die Anwendung Details der Zugangsberechtigung erhält. Das typische „Loggen Sie sich einfach mit Facebook ein“-Ding. Der große Vorteil ist hier, dass keine Passwörter weitergegeben werden, sondern lediglich sog. Access-Tokens generiert werden, die in der Regel auch eine Verfallsdatum haben. Alles crispy, alles funky, aber eben auch alles etwas komplizierter.

Wie gesagt war der Anlass, mich wieder mal mit dem Thema zu befassen, die Reaktivierung des Backups meiner Google Kontakte mit dem Raspberry Pi. Deshalb werde ich hier mal kurz umreißen, wie das Prozedere jetzt aussieht.

Der PHP-Code

Mir ist klar, dass sich meine PHP-Künste im Rahmen halten. Der Code hier ist also nur zum Hausgebrauch und als Arbeitsgrundlage für weitere Optimierungen geeignet. Außerdem enthält er eine Reihe an Kommentaren, die eher den Stil eines Selbstgesprächs als einer sinnvollen Code-Kommentierung haben. Egal.


<?

		// Backup der Google Kontakte per Cronjob funktioniert nur noch mit OAuth2

		// Es gäbe jetzt 2 Wege:

		// 1) User authentifiziert sich per Web

		// 	Problem:
		// 	- Die Authentifizierung läuft schnell ab.
		// 	- Daher ist das per Skript nicht praktikabel.

		// 2) Authentifizierung über ein "Dienskonto" ("service account") mit einem P12-Schlüssel

		// 	Problem:
		// 	- Das Dienstkonto mit seiner speziell generierten Mailadresse kann sich zwar dauerhaft authentifizieren,
		// 	  hat aber keinen Zugriff auf die Kontakte des Users, der das Dienstkonto erstellt hat...

		// Hinweise:

		// - Erstellen eines Projekts bei Google und erzeugen der Schlüssel:		https://console.developers.google.com/project
		// - API Client Library for PHP:											https://developers.google.com/api-client-library/php/start/get_started
		// - Google Contacts API version 3.0:										https://developers.google.com/google-apps/contacts/v3/index#retrieving_all_contacts
		// - google-api-php-client:													https://github.com/google/google-api-php-client
		// - Beispielcode für Ahthentifizierung per Web:							https://github.com/google/google-api-php-client/issues/462
		// - Warum es nicht geht, sondern nur mit einer "Google managed domain":	http://stackoverflow.com/questions/14407415/accessing-google-contacts-api-via-oauth-2-0-and-private-key-aka-service-account
		// - Vielleicht geht es doch per Web-Authentifizierung???					http://stackoverflow.com/questions/13851157/oauth2-and-google-api-access-token-expiration-time

		//  >>> However, after a successful completion of the OAuth2 installed application flow,
		// 		you will get back a refresh token.
		// 		This refresh token never expires, and you can use it to exchange it for an access token as needed.
		// 		Save the refresh tokens, and use them to get access tokens on-demand
		// 		(which should then immediately be used to get access to user data).

# Debug-Modus. Wenn der TRUE ist werden nur Debug-Infos rausgeschickt:
define("DEBUGMODUS", FALSE);

# # # # VERSION MIT DER WEB-AUTHENTIFIZIERUNG

	# Diese Daten hier erhält man nach der Registrierung eines Projekts in der Developers Console (https://console.developers.google.com/):
	# Client-ID:
	$client_id 		= 'HIER KOMMT DEINE CLIENT-ID REIN';
	# Clientschlüssel:
	$client_secret 	= 'HIER KOMMT DEIN CLIENT-SCHLÜSSEL REIN';

	# Nach dem ersten Aufruf des Skripts per Webbrowser bekommt man einen RefreshToken,
	# den man hier einträgt. Mit diesem kann dann bei jedem weiteren Aufruf
	# ein neuer AccessToken geholt werden, mit dem dann wiederrum die Daten geholt werden:
	$refresh_token = 'HIER KOMMT DEIN REFRESH-TOKEN REIN';

	/*
	 * Copyright 2011 Google Inc.
	 *
	 * Licensed under the Apache License, Version 2.0 (the "License");
	 * you may not use this file except in compliance with the License.
	 * You may obtain a copy of the License at
	 *
	 *     http://www.apache.org/licenses/LICENSE-2.0
	 *
	 * Unless required by applicable law or agreed to in writing, software
	 * distributed under the License is distributed on an "AS IS" BASIS,
	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	 * See the License for the specific language governing permissions and
	 * limitations under the License.
	 */

	# Falls das Skript per Kommandozeile ausgeführt werden soll sollen die Fehler unterdrückt werden (z.B. die Warnings wg. der Session):
	if ($refresh_token)	error_reporting(0);

	session_start();

	// # Session manuell killen, und damit neue Token erzwingen:
	// unset($_SESSION['access_token']);

	# Diese Library muss eingebunden werden: https://github.com/google/google-api-php-client
	require_once __DIR__ . '/google-api-php-client-master/examples/templates/base.php';
	require_once __DIR__ . '/google-api-php-client-master/src/Google/autoload.php';

	$scriptUri 		= "http://".$_SERVER["HTTP_HOST"].$_SERVER['PHP_SELF'];
	$redirect_uri 	= $scriptUri;

	/************************************************
	  Make an API request on behalf of a user. In
	  this case we need to have a valid OAuth 2.0
	  token for the user, so we need to send them
	  through a login flow. To do this we need some
	  information from our API console project.
	 ************************************************/
	$client = new Google_Client();
	$client->setClientId($client_id);
	$client->setClientSecret($client_secret);
	$client->setRedirectUri($redirect_uri);
	//$client->addScope("https://www.googleapis.com/auth/contacts.readonly");
	$client->addScope("https://www.google.com/m8/feeds");

	# HIER KOMMT DER ENTSCHEIDENDE PUNKT!
	# Der AccessToken soll OFFLINE sein, d.h. ich bekomme auch einen 'refresh_token',
	# mit dem ich mir dann immer wieder neu einen 'access_token' holen kann,
	# ohne die Web-Authentifizierung neu machen zu müssen.
	# Siehe https://developers.google.com/identity/protocols/OAuth2WebServer#refresh
	# PHP-Demo: http://stackoverflow.com/questions/9241213/how-to-refresh-token-with-google-api-client
	# Außerdem muss dazu noch approval_prompt=force gesetzt werden.
	# Siehe https://github.com/google/google-api-php-client/issues/263
	$client->setAccessType('offline');
	$client->setApprovalPrompt('force');

	/************************************************
	  Boilerplate auth management - see
	  user-example.php for details.
	 ************************************************/
	if (isset($_REQUEST['logout'])) {
		unset($_SESSION['access_token']);
	}
	if (isset($_GET['code'])) {
		$client->authenticate($_GET['code']);
		$_SESSION['access_token'] = $client->getAccessToken();
		$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
		header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
	}

	if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
		$client->setAccessToken($_SESSION['access_token']);
	} else {
		$authUrl = $client->createAuthUrl();
	}

	# Falls schon ein RefreshToken gesetzt ist kann das Skript per Kommandozeile ausgeführt werden:
	if ($refresh_token) {

		# Damit hole ich mir bei JEDEM Aufruf einfach einen neuen Access-Token ;-)
		$client->refreshToken($refresh_token);

		# Außerdem die Variable $authUrl löschen, sonst wird weiter unten nur die URL zum Login angezeigt:
		unset($authUrl);
	}

	/************************************************
	  If we're signed in, retrieve contacts
	 ************************************************/
	if ($client->getAccessToken()) {

		if (DEBUGMODUS) echo "<hr><h1>Session-Variablen:</h1><pre>".print_r($_SESSION, true)."</pre>";

		$_SESSION['access_token'] = $client->getAccessToken();

		$access_token = json_decode($client->getAccessToken())->access_token;
		if (DEBUGMODUS) echo "<hr><h1>Client:</h1><pre>".print_r($client, true)."</pre>";
		if (DEBUGMODUS) echo "<hr><h1>Access-Token:</h1><pre>".print_r(json_decode($client->getAccessToken()), true)."</pre>";
		if (DEBUGMODUS) echo "<hr><h1>Weitere Infos zum Access-Token:</h1><pre>".print_r(json_decode(file_get_contents('https://www.googleapis.com/oauth2/v3/tokeninfo?access_token='.$access_token)), true)."</pre>";

		# Beim ersten Aufruf soll einfach nur der Refresh-Token zurückgegeben werden, der muss dann hier ins Skript eingetragen werden:
		if (!$refresh_token) {
			echo "Bitte den Code unterhalb der Linie in das Skript in die Variable $refresh_token eintragen:<hr>";
			echo "<pre>".json_decode($client->getAccessToken())->refresh_token."</pre>";
			exit();
		}

		//$url = 'https://www.google.com/m8/feeds/contacts/default/full?max-results=3&alt=json&v=3.0&oauth_token='.$access_token;
		$url = 'https://www.google.com/m8/feeds/contacts/default/full?max-results=3000&alt=json&v=3.0&oauth_token='.$access_token;

		$response =  file_get_contents($url);

	}
	if (isset($authUrl)) {
		echo "<a class='login' href='" . $authUrl . "'>Zugriff auf Google Contacts autorisieren > KLICK!</a>";
	} else {
		if (DEBUGMODUS) echo "<hr><h1>Kontakte:</h1><pre>".print_r(json_decode($response), true)."</pre>";
		else echo $response;

	}

Dieses Skript muss auf den Raspberry Pi kopiert und so eingerichtet werden, dass es (vorübergehend) aus dem Netz erreichbar ist. Man sollte also irgend einen Webserver auf dem Pi laufen haben.

Außerdem braucht man den Google API PHP-Client, den man herunterladen und in sein Projekt einbinden muss. Könnte man auch per Composer machen, ist in diesem Fall aber vielleicht ein bisschen zu viel des Guten. Immerhin gibt es keine Abhängigkeiten von anderen Paketen.

Die Authentifizierung

Um dem Skript nun Zugriff auf die eigenen Daten zu gewähren, muss in der Google Developers Console ein neues Projekt angelegt werden: https://console.developers.google.com/ Das Projekt braucht einen beliebigen Namen. Außerdem muss man folgende APIs aktivieren:

  • Contacts API
  • Google Contacts CardDAV API
  • Google Partners API

Bin mir nicht wirklich sicher, ob man die „Google Contacts CardDAV API“ hier auch braucht, aber sie schadet nicht…

Anschließend brauchen wir Zugangsdaten, die wir (tataaa!) unter „Zugangsdaten“ generieren. Und zwar wählen wir „Client-ID für Webanwendung erstellen“. Wichtig ist an dieser Stelle, dass eine Weiterleitungs-URI gesetzt wird, die auf genau die URL zeigt, unter der unser PHP-Skript gerade im Netz erreichbar ist. Wenn wir die Client-ID erstellt haben bekommen wir unter anderem folgende Parameter: Eine „Client-ID“ und einen sog. „Clientschlüssel“. Diese beiden Werte müssen wir jetzt in unser PHP-Skript eintragen:


# Diese Daten hier erhält man nach der Registrierung eines Projekts in der Developers Console (https://console.developers.google.com/):
 # Client-ID:
 $client_id = 'HIER KOMMT DEINE CLIENT-ID REIN';
 # Clientschlüssel:
 $client_secret = 'HIER KOMMT DEIN CLIENT-SCHLÜSSEL REIN';

Wenn wir jetzt das PHP-Skript vom Web aus aufrufen, können wir den bekannten Authentifizierungsprozess starten: Das Skript leitet weiter zu einer Google-Authentifizierungsseite, dort sollte man dann alles gut finden und brav bestätigen, und am Ende wird man zurück zu unserem Skript geleitet. Das Skript ist jetzt authentifiziert, die Kontakte bei Google abzuholen. Allerdings verfällt der dazu vergeben Access Token schon innerhalb einer Stunde. Unpraktisch, wenn das Skript die Kontakte z.B. täglich ohne Zutun des Nutzers sichern soll. Daher wird von Google gleichzeitig ein sog. „Refresh Token“ angefordert. Mit Hilfe dieses Refresh Tokens kann das Skript bei jedem Aufruf einen neuen Access Token anfordern und anschließend mit diesem die Kontakte anfordern. Dazu muss man den Refresh Token irgendwo hinterlegen. Üblicherweise macht man das in einer Datenbank, der Einfachheit halber speichern wir ihn aber direkt im Skript. Das Skript zeigt den Refresh Token nach erfolgreicher Authentifizierung im Browser an, von dort kopieren wir ihn jetzt in unser Skript:


# Nach dem ersten Aufruf des Skripts per Webbrowser bekommt man einen RefreshToken,
# den man hier einträgt. Mit diesem kann dann bei jedem weiteren Aufruf
# ein neuer AccessToken geholt werden, mit dem dann wiederrum die Daten geholt werden:
$refresh_token = 'HIER KOMMT DEIN REFRESH-TOKEN REIN';

Die Ausführung

Ein Zugriff auf das Skript über das Internet ist nun nicht mehr nötig und sollte auch unterbunden werden. Denn ab jetzt soll das Skript nur noch per Kommandozeile oder Crontab ausgeführt werden, z.B. so:

php ~/skripte/backup-google-contacts.php | gzip > ~/backup/Google\ Kontakte/backup-google-contacts-`date +\%Y-\%m-\%d`.json.gz

Geschafft! Ich hoffe, der eine oder andere kann etwas mit dem Code-Chaos hier anfangen. Der Code sollte auf jeden Fall ein paar Anhaltspunkte für jemanden enthalten, der vor ähnlichen Problemen steht. Ich glaube, mir hätte das eine oder andere Code-Schnipsel weitergeholfen und mir die eine oder andere Nachtschicht erspart. Wobei, wäre vielleicht sogar schade gewesen, so ein Erfolgserlebnis ist ja auch was wert 😉

Flugzeuge tracken

Vor einigen Wochen lag in meinem Briefkasten ein kleiner, billiger DVB-T-Stick, mit dem man üblicherweise digitales terrestrisches Fernsehen z.B. am Laptop empfängt. Absender des Päckchens war mein Cousin Johannes, und langsam dämmerte es mir, dass er mich nicht zum Fernsehen animieren wollte. Man kann diese DVB-T-Sticks nämlich dazu verwenden, um die ADS-B-Signale von Flugzeugen zu empfangen und diese damit zu tracken. Klingt nach einer Spielerei, und ja, das ist es auch.

Ich hatte gesehen, dass Johannes schon einige Blogartikel zu dieser Sache geschrieben hatte:

Grob gesagt geht es darum, dass man mit diesen Empfängern die Flugdaten von Flugzeugen abgreifen und diese dann in verschiedener Form darstellen kann. Ein typisches Beispiel ist die Seite flightradar24.com, auf der man dem weltweiten zivilen Luftverkehr quasi in Echtzeit zuschauen kann. Und diese Daten kommen unter anderem von solchen kleinen DVB-T-Empfängern, um die es hier geht. Schon irgendwie faszinierend.

Im Detail läuft das so: Ich habe den besagten DVB-T-Empfänger bei uns im 1. Stock außen an ein Balkongitter geklemmt und ihn an meinen Raspberry Pi angeschlossen. Die Position ist nicht ideal, aber ein Anfang. Ich wollte einfach nahe am Standort des Raspberry Pis sein. Dann habe ich strickt nach dieser sehr guten und ausführlichen Anleitung die Treiber und die Software dump1090 installiert. Mehr Details dazu findet man auch in den oben verlinkten Artikeln von Johannes, daher erspare ich mir (und euch) das an dieser Stelle. Das Programm zieht ca. 30% der CPU-Leistung des Raspberry Pis, dafür liefert es dauerhaft eine ganze Reihe Flugdaten:

ADS-B

Die von meinem Empfänger im Moment empfangenen Flugzeuge, dargestellt von dump1090.

Diese stelle ich über diverse geöffnete Ports im Router auch der Welt da draußen und damit auch dem eigenen Virtual Radar Server von Johannes zur Verfügung. Dieses Programm stellt die von ihm empfangenen Flugzeuge sehr schön da, man kann einzelne Maschinen anklicken und ganz viele Details zu dem Flug einsehen. Steht dort bei einem Flugzeug als Receiverstandort „Würzburg“, dann kommen die Daten von mir. Vorher betrieb Johannes zwei Empfänger, einen südlich und einen nördlich von Frankfurt:

VRS-Landungen-2014-03-16-Sonntag-20-Uhr

Die beiden bisherigen Empfängerstandorte von Johannes.

Und im Osten von Frankfurt kommt jetzt also noch Würzburg dazu. Unbedingt mal reinschauen: http://planes.webernetz.net/virtualradar/

 

Nachtrag

Man kann sich im VIrtual Radar auch die Reichweite eines einzelnen Empfängers ansehen. Obwohl meiner seitlich am Haus sitzt und somit eher nach Westen schaut sieht die Verteilung recht homogen aus:

Receiver Range

 

Raspberry Pi als Backupmaschine

Raspberry PiDer Raspberry Pi ist eine kleine Allzweckwaffe: Ein kompletter Rechner für ca. 35€, so groß wie eine Scheckkarte und mit einer sehr geringen Leistungsaufnahme (deren Kehrseite natürlich auch eine ziemlich geringe Leistung ist). Aber für manche Anwendungsfälle ist der Raspberry Pi genau das richtige Gerät. Ich kenne einige Leute, die sich vor lauter Begeisterung einen Raspberry Pi gekauft haben und nun nicht so richtig wissen, was sie mit dem schicken Teil nun eigentlich anfangen sollen. Mein Tipp: Als Backupmaschine verwenden.

Was der Raspberry Pi bei mir alles so backupt will ich in diesem Beitrag grob skizzieren. Voraussetzung ist ein fertig installiertes Raspian oder ein vergleichbares System, Grundkenntnisse im Umgang mit Linux (z.B. der crontab), dem Raspberry Pi an sich und zumindest eine gewisse Lernbereitschaft und Offenheit gegenüber z.B. Shell- und PHP-Skripten. Ich werde keine kompletten Anleitungen schreiben, eher so eine Gedankensammlung. Es muss und soll also weiter gebastelt und gegooglet werden!

Weiterlesen

RSS-Feeds in Feedly abonnieren (Chrome)

Irgendwann im Laufe dieses Tages wird der gute alte Google Reader abgeschaltet werden. Ich werde ihn schon etwas vermissen, denn er war seit Jahren eines meiner wichtigsten Tools, um mich über die verschiedensten Themen auf dem Laufenden zu halten. Nun gut, die Entscheidung von Google hat auch einen positiven Nebeneffekt: Das Thema RSS – von einigen lange totgesagt – wird wieder etwas belebt. Neue Reader sprießen aus dem Boden, die neue Konkurrenz belebt das Geschäft, Handling und Design eines RSS-Readers werden hier und da neu überdacht und neu erfunden. Ich habe mich – wie vermutlich ein Großteil der Umsteiger – erst mal für Feedly als Nachfolger für den Google Reader entschieden. Mit scheint das einfach die solideste und umtriebigste Alternative zu sein. Man hat dort in den letzten Wochen mächtig Gas gegeben: Der Umstieg vom Google Reader ist ein Kinderspiel, der Reader wurde an die Gewohnheiten der Google-Reader-User angepasst, man hat die Browser-Erweiterung für die Nutzung des webbasierten Readers obsolet gemacht und vieles mehr.

Ganz praktisch hab ich mich vorhin aber gefragt, wie ich denn nun in Chrome einen neuen Feed zu Feedly hinzufügen kann. Klar kann man händisch die Feed-Adresse herausfinden und bei Feedly hinzufügen. Auf Dauer finde ich aber diese Weg praktischer:

Weiterlesen