// Über externe Wetterdaten

Leider hat YAHOO! den Wetterservice vor einer Woche umgestellt. Damit funktionierte folgende Methode zum Auslesen der externen Wetterdaten (als Vergleich) nicht mehr:

#Humidity
w3m -dump http://weather.yahoo.com/germany/baden-wurttemberg/schutterwald-12836276/?unit=c | grep -A21 "Current" | sed 's/DEG/°/g' | head -9 | tail -n1 | awk '{print $1}'
 
#Temperature
w3m -dump http://weather.yahoo.com/germany/baden-wurttemberg/schutterwald-12836276/?unit=c | grep -A25 "Current" | sed 's/DEG/°/g' | head -n25 | tail -n1
 
#Dewpoint
w3m -dump http://weather.yahoo.com/germany/baden-wurttemberg/schutterwald-12836276/?unit=c | grep -A21 "Current" | sed 's/DEG/°/g' | head -n13 | tail -n1 | awk '{print $1}'

Da ich zu dieser Zeit auf Studienfahrt in Prag war, konnte ich mich erst letztem Wochenende diesem Problem widmen. Für diese Zeit fehlten dann leider die externen Wetterdaten:

Eine provisorische Lösung

Die Daten von YAHOO! sind eigentlich nicht zu gebrauchen: es fehlen Taupunkt und rel. Luftfeuchtigkeit und ohne Javascript ist das Auslesen nur in °F möglich :-(
Da YAHOO aber im Endeffekt auch nur Wetterdaten von TheWeatherChannel verwendet habe ich mir TWC mal genauer angeschaut:

  • Die amerikanische Seite ist genauso schwer auslesbar,…
  • die deutsche Unterseite hingegen scheint etwas hinterher zu sein (Tabellenlayout…)

…und bot mir die ideale Möglichkeit für eine provisorische Lösung:

#wget verwenden, w3m -dump schlechte Idee, w3m -dump_source funtzt nicht
TWC_TMP="/tmp/weather_twc_tmp"
wget "http://de.weather.com/weather/local/77746?x=0&y=0" -O $TWC_TMP > /dev/null 2>&1
 
#Dewpoint
cat $TWC_TMP | grep -A2 Taupunkt | tail -n 1 | cut -d '>' -f 2 | cut -d'&' -f1
 
#Humidity
cat $TWC_TMP | grep -A2 Luftfeuchtigkeit | tail -n 1 | cut -d '>' -f 2 | cut -d'%' -f1
 
#Temperature
cat $TWC_TMP | grep '<TD COLSPAN="2"' | head -n 1 | cut -d ';' -f 2 | cut -d '&' -f 1

Mehr als eine provisorische Lösung ist das aber nicht. Sobald die Seite relaunched wird (bei dem Layout wohl bald) oder gewisse Dinge verändert werden, hocke ich vor dem gleichen Problem. Ich hasse es von externen Anbietern abhängig sein zu müssen.

Richtige APIs

Längerfristig muss man folglich auf APIs zurückgreifen. Hier existieren zwei erwähnenswerte:

TheWeatherChannel bietet ebenfalls eine API an - allerdings nicht kostenlos. Wenn du weitere oder bessere Wetter APIs kennst, würde ich mich über einen Kommentar freuen.

YAHOO! Weather API

Die YAHOO API ist aber ähnlich unbrauchbar wie der Webdienst. Es fehlen wieder Taupunkt und rel. Luftfeuchtigkeit. Ist aber einfacher auslesbar als der Webdienst. Die URL setzt sich wie folgt zusammen:

http://weather.yahooapis.com/forecastrss?w=[Ortsid]&u=[Einheit (hier °C, also c]

Die Ortsid lässt sich aus der URL des Webservices bestimmen. Dazu muss man hier nach dem passenden Ort suchen. Anschließend kann man aus der URL die ID auslesen - Beispiel (ID hier: 693419):

http://weather.yahoo.com/germany/baden-wurttemberg/schutterwald-693419/

Nun kann man sich die URL „zusammenbauen“ (Fortführung vorheriges Beispiel):

http://weather.yahooapis.com/forecastrss?w=693419&u=c

Google Wetter API

In der API von Google findet auch die rel. Luftfeuchtigkeit. Der Taupunkt fehlt aber ebenfalls. Die URL setzt sich wie folgt zusammen:

http://www.google.com/ig/api?weather=[PLZ]&hl=[Sprache]

Folglich müsste ich diese URL verwenden:

http://www.google.com/ig/api?weather=77746&hl=de

Das Auslesen dürfte überhaupt kein Problem darstellen.

// Neue Hardware – Intel Pentium G630T & Co

Zurzeit arbeite ich an einem neuen System für Hosting/Virtualisierung – die alte Hardware reicht einfach nicht mehr aus. Dazu habe ich mich zu folgender Hardware entschieden:

Insgesamt ein relativ preiswertes und sparsames System, dass aber über genügend Ressourcen für rechenintensive Applikationen verfügt. Wie es damit weiter geht und welche Erfahrungen ich mit dieser Hardware sammeln werde, wirst du bald auf mein.homelinux.com erfahren. Zusammengebaut sieht das Ganze so aus:

// Weather.chrisge.org – Die Software III/III: Munin & Fazit

Nachdem ich das Projekt Weather.chrisge.org bereits in Grundzügen erläutert habe und die verwendete Hardware ebenfalls vorgestellt habe, werde ich in diesem Beitrag auf die Softwarekonfiguration eingehen. Da der gesamte Entwicklungsprozess mehrere Monate in Anspruch nahm, werde ich nur auf die wichtigsten Dinge eingehen. Zu einem späteren Zeitpunkt werde ich gegebenenfalls eine Dokumentation im mein.homelinux.com Wiki erstellt. Falls Fragen auftauchen sollten: melden!

Dieser Beitrag ist Teil der Serie Weather.chrisge.org:

Diese Anleitung dürfte mit Debian-basierende Linux-Distributionen (z.B. Ubuntu) kompatibel sein. Die Munin Plugins müssten aber auf jeder Linux Plattform funktionsfähig sein. Ich habe sie bis jetzt aber nur mit Debian Squeeze getestet.

Graphen: Munin

Die Graphen erzeuge ich mit Munin. Der Vorteil ist, dass ich die Graphen auf einem anderen System rendern kann, also die Wetterstation ein sehr leistungsschwaches System (nur Munin-Node) sein kann, während das andere System (Munin) die Daten graphed und präsentiert, wofür mehr Leistung erforderlich ist. Zu Munin habe ich bereits eine Anleitung geschrieben:

Darin wird die Architektur von Munin (Munin u. Munin-Node) sowie die Installation und die Einrichtung näher erläutert. Diese Anleitung ist absolute Basis für diese Anleitung. Munin muss bereits voll einsatzfähig und konfiguriert sein.

Plugins

Da kein Plugin finden konnte, dass meinen erwünschten Zweck erfüllt, musste ich selbst drei Munin-Plugins schreiben. Wie dies geht, wird im Munin Wiki beschrieben.

Die Plugins werden in /usr/share/munin/plugins/ gespeichert und anschließend nach /etc/munin/plugins verlinkt:

$ sudo ln -s /usr/share/munin/plugins/PLUGIN /etc/munin/plugins/
$ sudo /etc/munin/munin-node restart    #Munin-Node neustarten

Meine Plugins holen jew. noch die Daten von YAHOO! Weather und legen eine Statusdatei an, die immer den zuletzt ausgelesenen Wert anzeigen. Der Code ist nicht wirklich gesäubert und muss, wenn die Plugins verwendet werden sollen noch angepasst werden! Sie sollen nur Beispiele sein!
Folgendes muss angepasst werden:

  • Der Pfad zum Sensor
  • Das Statfile
  • Die URL zum YAHOO! Weather Wetterbericht

Luftfeuchtigkeit

humidity
#!/bin/sh
# Simple OWFS Humidity Munin Plugin
# Copyright: (C) 2012 Christoph Winkler <cw[at]chrisge[dot]org>
# Web: http://www.chrisge.org / http://weather.chrisge.org
# License: GPL-3 <http://www.gnu.org/licenses/gpl-3.0.txt>
 
if [ "$1" = "config" ]; then
 
echo 'graph_title Humidity (Luftfeuchtigkeit)'
echo 'graph_args --rigid'
echo 'graph_vlabel Relative Humidity in %'
echo 'graph_scale no'
echo 'graph_category Weather'
 
echo 'screen0.label Local Relative Humidity'
echo 'real0.label Adapted from YAHOO! Weather'
 
echo 'real0.draw LINE1'
 
exit 0
fi
 
TWC_TMP="/tmp/weather_twc_tmp"
wget "http://de.weather.com/weather/local/77746?x=0&y=0" -O $TWC_TMP > /dev/null 2>&1
 
REAL=$(cat $TWC_TMP | grep -A2 Luftfeuchtigkeit | tail -n 1 | cut -d '>' -f 2 | cut -d'%' -f1)
STATE_R="/tmp/humidity_r"
 
echo $REAL > $STATE_R
 
BASE="/media/owfs"
 
SENSOR_0="26.E67023010000"
STATE_0="/tmp/humidity_0"
 
if test -d ${BASE}/$SENSOR_0
then
  SCREEN_0=$(cat ${BASE}/$SENSOR_0/humidity ; echo)
  echo $SCREEN_0 > $STATE_0
  echo screen0.value $SCREEN_0
fi
 
echo real0.value $REAL

Temperatur

temperature
#!/bin/sh
# Simple OWFS Temperature Munin Plugin
# Copyright: (C) 2012 Christoph Winkler <cw[at]chrisge[dot]org>
# Web: http://www.chrisge.org / http://weather.chrisge.org
# License: GPL-3 <http://www.gnu.org/licenses/gpl-3.0.txt>
 
if [ "$1" = "config" ]; then
echo 'graph_title Temperatures (Temperaturen)'
echo 'graph_args --base 1000'
echo 'graph_vlabel Temperature in Celsius'
echo 'graph_category Weather'
echo 'graph_scale no'
 
echo "screen0.label Outdoor Sensor one"
echo "screen1.label Outdoor Sensor two"
echo "case0.label Outdoor in Sun"
echo "real0.label Adapted from YAHOO! Weather"
 
echo 'real0.draw LINE1'
 
exit 0
fi
 
BASE="/media/owfs"
 
SENSOR_0="26.E67023010000"
SENSOR_1="28.75798C020000"
SENSOR_2="28.4F523C020000"
 
STATE_0="/tmp/temperature_scr_0"
STATE_1="/tmp/temperature_scr_1"
STATE_2="/tmp/temperature_cas_0"
 
TWC_TMP="/tmp/weather_twc_tmp"
wget "http://de.weather.com/weather/local/77746?x=0&y=0" -O $TWC_TMP > /dev/null 2>&1
 
REAL=$(cat $TWC_TMP | grep '<TD COLSPAN="2"' | head -n 1 | cut -d ';' -f 2 | cut -d '&' -f 1)
STATE_R="/tmp/temperature_r"
 
echo $REAL > $STATE_R
 
if test -d ${BASE}/$SENSOR_0
then
  SCREEN_0=$(cat ${BASE}/$SENSOR_0/temperature ; echo)
  echo $SCREEN_0 > $STATE_0
  echo screen0.value $SCREEN_0
fi
 
if test -d ${BASE}/$SENSOR_1
then
  SCREEN_1=$(cat ${BASE}/$SENSOR_1/temperature ; echo)
  echo $SCREEN_1 > $STATE_1
  echo screen1.value $SCREEN_1
fi
 
if test -d ${BASE}/$SENSOR_2
then
  CASE_0=$(cat ${BASE}/$SENSOR_2/temperature ; echo)
  echo $CASE_0 > $STATE_2
  echo case0.value $CASE_0
fi
 
echo real0.value $REAL

Dewpoint

Der Dewpoint → Taupunkt kann aus der relativen Luftfeuchtigkeit sowie der Temperatur errechnet werden. Mein Plugin bassiert auf diesem Skript und benötigt unbedingt das Paket bc.

dewpoint
#!/bin/sh
# Simple OWFS Humidity Munin Plugin
# Copyright: (C) 2012 Christoph Winkler <cw[at]chrisge[dot]org>
# Web: http://www.chrisge.org / http://weather.chrisge.org
# License: GPL-3 <http://www.gnu.org/licenses/gpl-3.0.txt>
# Based On: http://www.lawbiz.ch/d/spahni/programs/relhumidity.html
 
if [ "$1" = "config" ]; then
echo 'graph_title Dewpoint (Taupunkt)'
echo 'graph_args --base 1000'
echo 'graph_vlabel Dewpoint in Celsius'
echo 'graph_category Weather'
echo 'graph_scale no'
 
echo "screen0.label Local Dewpoint"
echo "real0.label Adapted from YAHOO! Weather"
 
echo 'real0.draw LINE1'
exit 0
fi
 
BASE="/media/owfs"
 
SENSOR_0="26.E67023010000"
STATE_0="/tmp/dewpoint_0"
 
TEMPERATURE="$(cat ${BASE}/$SENSOR_0/temperature ; echo)"
HUMIDITY="$(cat ${BASE}/$SENSOR_0/humidity ; echo)"
 
TWC_TMP="/tmp/weather_twc_tmp"
wget "http://de.weather.com/weather/local/77746?x=0&y=0" -O $TWC_TMP > /dev/null 2>&1
 
REAL=$(cat $TWC_TMP | grep -A2 Taupunkt | tail -n 1 | cut -d '>' -f 2 | cut -d'&' -f1)
STATE_R="/tmp/dewpoint_r"
 
echo $REAL > $STATE_R
 
if test -d ${BASE}/$SENSOR_0
then
SCREEN_0=$(echo "define pa (n) {
         if (n >= 0.0) {
            return (7.5);
         } else {
            return (7.6);
         }
      }
 
      define pb (n) {
         if (n >= 0.0) {
            return (237.3);
         } else {
            return (240.7);
         }
      }
 
      define sdd (t) {
         return (6.1078 * e( l(10) * ((pa(t) * t) / (pb(t) + t)) ) );
      }
 
      define dd (r,t) {
         return (r / 100.0 * sdd(t));
      }
 
      /* factor 2.302585093 converts ln() to log() */
      v  = l(dd($HUMIDITY,$TEMPERATURE) / 6.1078) / 2.302585093;
      tp = ((pb($TEMPERATURE) * v) / (pa($TEMPERATURE) - v));
 
      if ( tp >= 0.0 ) {
         tp = (tp + 0.05);
      } else {
         tp = (tp - 0.05);
      }
 
      scale = 4;
      (tp / 1.0); " | bc -l)
 
  if [ "$(echo $SCREEN_0 | head -c 1)" = "." ] ; then SCREEN_0=0${SCREEN_0}
    elif [ "$(echo $SCREEN_0 | head -c 2)" = "-." ] ; then SCREEN_0=-0${SCREEN_0#-}
  fi
 
  echo $SCREEN_0 > $STATE_0
  echo screen0.value $SCREEN_0
 
fi
 
echo real0.value $REAL

Fazit & Ausblick

Inspiriert wurde ich durch Dave's & Max's Weather-Station/Cam von der ich damals in Doozan's Forum erfahren habe. Das ganze Projekt war eine einzige große Bastelei. Ich hatte zu keinem einzigen Baustein eine vollständige Dokumentation. Letzten Endes habe ich nach einigem Herumprobieren dann doch immer eine Lösung gefunden. Unter anderem deshalb habe ich das Grundgerüst für andere Bastler dokumentiert. Wenn dir Angaben fehlen oder etwas unklar erscheint, stehe ich dir gerne zur Verfügung.

Es ist immer wieder erstaunlich zu sehen, was man mit kleiner Embedded ARM-Hardware so alles hin bekommt. Als nächstes werde ich den 1-Wire Bus durch weitere Sensoren erweitern und ggf. das System in ein wetterfestes Gehäuse draußen platzieren - im Moment steht es noch drinnen. In diesem Zusammenhang warte ich auf den Raspberry Pi, der für eine Wetterstation wirklich genial ist.

Probleme

Das größte Problem ist, dass der USB-Hub in unregelmäßigen Abständen resetet wird und der 1-Wire Adapter dann nicht mehr als ttyUSB0 sondern ttyUSB1 angemeldet wird. OWFS verliert dann den Bus, bis der Adapter abgesteckt und erneut angeschlossen wird (erscheint wieder las ttyUSB0).
Manchmal verliert Motion bei diesem Vorfall die Webcam, beendet sich und muss anschließend wieder gestartet werden.

// Weather.chrisge.org – Die Software II/III: OWFS

Nachdem ich das Projekt Weather.chrisge.org bereits in Grundzügen erläutert habe und die verwendete Hardware ebenfalls vorgestellt habe, werde ich in diesem Beitrag auf die Softwarekonfiguration eingehen. Da der gesamte Entwicklungsprozess mehrere Monate in Anspruch nahm, werde ich nur auf die wichtigsten Dinge eingehen. Zu einem späteren Zeitpunkt werde ich gegebenenfalls eine Dokumentation im mein.homelinux.com Wiki erstellt. Falls Fragen auftauchen sollten: melden!

Dieser Beitrag ist Teil der Serie Weather.chrisge.org:

Dieser Post ist bezüglich OWFS Verwendung (nicht Installation) nur für die in den obigen Beiträgen vorgestellte 1-Wire Hardware gültig, kann aber problemlos auf andere übertragen werden. Kompatible Betriebssysteme sollten Debian-basierende Linux-Distributionen (z.B. Ubuntu) sein. Ich habe sie bis jetzt aber nur mit Debian Squeeze getestet.

1-Wire: OWFS

Um die Werte der Sensoren auszulesen verwende ich, wie bereits erwähnt OWFS. Da OWFS nicht in den Paketquellen vorhanden ist, muss es manuell komplimiert werden. Dazu findet sich hier eine detaillierte Anleitung.

Vorbereitungen

Zuerst müssen diverse Kernelmodule deaktiviert werden:

$ sudo modprobe -r ds9490r
$ sudo modprobe -r ds2490
$ sudo modprobe -r wire

…und anschließend in die /etc/modprobe.d/blacklist eingetragen werden:

# OWFS via libusb
blacklist ds9490r
blacklist ds2490
blacklist wire

Nun werden die für das Komplimieren benötigten Pakete installiert:

$ sudo apt-get install build-essential automake autoconf autotools-dev gcc g++ libtool fuse-utils libfuse-dev swig python2.5-dev tcl8.4-dev php5-dev

Komplimieren

libusb

Hier ist es wichtig darauf zu achten, dass man libusb-0.1 (LEGACY) verwendet und in jenem Unterverzeichnis die aktuellst Version bezieht. Zur Zeit dieses Posts wäre dies diese URL:

http://sourceforge.net/projects/libusb/files/libusb-0.1%20%28LEGACY%29/0.1.12/libusb-0.1.12.tar.gz/download

libusb lade ich mit wget wie folgt herunter (wer lieber seinen Browser verwendet, kann gerne jenen verwenden und die Datei nachher an den richtigen Ort verschieben):

$ wget http://sourceforge.net/projects/libusb/files/libusb-0.1%20%28LEGACY%29/0.1.12/libusb-0.1.12.tar.gz/download -O libusb.tar.gz
$ tar xvzf libusb.tar.gz
$ cd libusb-0.1.12/

Nun komplimieren wir libusb:

libusb-0.1.12$ make
libusb-0.1.12$ sudo make install

Folgender Befehl (hier hat die verlinkte Anleitung einen Fehler):

$ libusb-config --version

…sollte 0.1.12 ausgeben.

OWFS

Zuerst besorgt man sich die aktuellste Version von OWFS auf sourceforge.net. In diesem Fall (Stand: Apr. 2012) lautet die URL wie folgt:

http://sourceforge.net/projects/owfs/files/latest/download?source=files

OWFS wird nun wie folgt heruntergeladen (Browser: siehe libusb:

$ wget http://sourceforge.net/projects/owfs/files/latest/download?source=files -O owfs.tar.gz

Nun entpacken wir das Paket:

$ tar xvzf owfs.tar.gz
$ cd owfs-2.8p14/

…anschließend kann der Build beginnen:

owfs-2.8p14$ ./configure --enable-debian
owfs-2.8p14$ make
owfs-2.8p14$ sudo make install

Erster Start

Wer OWFS ohne root-Rechte verwenden will, muss wie in der verlinkten Anleitung beschrieben noch etwas Hand an udev anlegen. Wer auf Nummer sicher gehen will, sollte diesen zusätzlichen Schritt durchführen. Dann könnte OWFS sowie OWSERVER ohne root-Rechte gestartet werden.

Ansonsten kann der 1-Wire Adapter (in meinem Fall der LinkUSB) mit dem fertigen 1-Wire Netz an den Rechner gehängt werden. Da jener Adapter über einen Seriellen Converter verfügt, müssten die benötigten Kernel Module normalerweise automatisch nachgeladen werden. Dies kann anhand der Ausgabe von dmesg | grep usb oder dem Syslog überprüft werden. Dort sollte folgende Meldung erscheinen:

[ 5996.029323] usb 1-1.2.4: new full speed USB device using orion-ehci and address 83
[ 5996.166193] usb 1-1.2.4: New USB device found, idVendor=0403, idProduct=6001
[ 5996.173435] usb 1-1.2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 5996.181097] usb 1-1.2.4: Product: FT232R USB UART
[ 5996.185945] usb 1-1.2.4: Manufacturer: FTDI
[ 5996.190237] usb 1-1.2.4: SerialNumber: A900fxuD
[ 5996.205792] usb 1-1.2.4: configuration #1 chosen from 1 choice
[ 5996.227183] usb 1-1.2.4: Detected FT232RL
[ 5996.231342] usb 1-1.2.4: Number of endpoints 2
[ 5996.235939] usb 1-1.2.4: Endpoint 1 MaxPacketSize 64
[ 5996.241057] usb 1-1.2.4: Endpoint 2 MaxPacketSize 64
[ 5996.246139] usb 1-1.2.4: Setting MaxPacketSize 64
[ 5996.252885] usb 1-1.2.4: FTDI USB Serial Device converter now attached to ttyUSB0

Sollte dies nicht der Fall sein, kann die Installation des Paketes libftdi1 helfen.
Aus der letzten Zeile geht hervor, dass der Adapter über /dev/ttyUSB0 angesprochen werden kann. OWFS (genauer gesagt OWSERVER) wird nun so gestartet:

$ sudo /opt/owfs/bin/owserver -p 4304 -d /dev/ttyUSB0 -t 30 --link --error_level 9

Aus einem mir bis jetzt unbekannten Grund, ist der Bus direkt nach dem Start nicht benutzbar. Ich warte normalerweise 5-10 Minuten und starte erst dann OWFS und binde damit den Bus als „Dateisystem“ ein:

$ sudo mkdir /media/owfs    #Anlegen des Mountpoints
$ sudo /opt/owfs/bin/owfs -s localhost:4304 --allow_other /media/owfs

Sollte das mit einer Fehlermeldung enden, dass kein 1-Wire Bus gefunden werden konnte, wartet man am besten einfach noch mal ein paar Minuten. Diese Unberechenbarkeit ist der Grund, dass ich kein Startskript einsetze, sondern OWFS immer per Hand starte. Das Problem liegt wahrscheinlich an der verwendeten Hardwarekonfiguration (Dockstar, USB-Hub und LinUSB) - mit einer anderen, könnte es ohne Probleme funktionieren.

Zusätzlich starte ich noch OWHTTPD:

$ /opt/owfs/bin/owhttpd -p 4305 -s localhost:4304

….und rufe nun die URL

http://host:4305

auf, die ein Listing des Buses anzeigt. Hier kann ich auch die Werte der Sensoren auslesen.

Werte auslesen

In obigem Beispiel wurde der Bus in /media/owfs gemountet. Folgendes befindet sich nun in dem Verzeichnis:

$ ls /media/owfs/
26.E67023010000  28.4F523C020000  28.75798C020000  alarm  bus.0  settings  simultaneous  statistics  structure  system  uncached

Die ZAHL.BLABLA benannten Verzeichnisse sind die IDs der Sensoren, in dem Verzeichnis befinden sich dann die Werte:

$ ls /media/owfs/26.E67023010000/
address  B1-R1-A  crc8  disconnect  endcharge  HIH3600  HTM1735   IAD  locator      offset  r_address  r_locator  temperature  udate  VDD
alias    CA       date  EE          family     HIH4000  humidity  id   MultiSensor  pages   r_id       S3-R1-A    type         VAD    vis

Der obige Sensor ist ein MS-TH, d.h. er verfügt über Temperatur und Luftfeuchtigkeit:

$ cat /media/owfs/26.E67023010000/humidity ; echo
     41.4725
$ cat /media/owfs/26.E67023010000/temperature ; echo
      7.5625

So kann man mit cat ganz einfach die Werte auslesen. Die Verwendung in Skripten ist somit wirklich einfach.

Hello World!

This is the personal website of Christoph Winkler aka chrisge.
Here you will find a sort of blog and some information about me and my projectshave fun!

Recent Comments
Latest Tweets
Follow me on Twitter...


QR Code: URL of current page
Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht: CC Attribution-Noncommercial-Share Alike 3.0 Unported