Der Gärtner kam durchs Netz (Linux-Magazin, März 2007)

Damit die Balkonpflanzen auch im Urlaub nicht vertrocknen, bauen wir heute ein Bewässerungssystem und lassen Linux zweimal täglich gießen.

Im Sommer genügen schon wenige Tage Abwesenheit, damit geliebte Balkonpflanzen wegen Wassermangels irreparable Schäden erleiden. Statt nach jedem Trip zum Supermarkt zu fahren, um totes Grünzeug zu ersetzen, sorgt eine Pumpe einfach für den nötigen Wassernachschub.

Schadensbegrenzung

Wer jedoch softwaregesteuert mit Wasser hantiert, läuft immer Gefahr, die Wohnung wegen eines unvorhergesehenen Fehlers unter Wasser zu setzen. Einen Ausweg aus diesem Dilemma zeigte eine unlängst im High-Tech Bastelmagazin ``Make'' vorgestellte Bewässerungslösung: Dort wurde einfach die verfügbare Wassermenge auf den Inhalt einer Wasserflasche beschränkt.

Abbildung 1: Der zweckentfremdede Hundekeksspender mit eingebauter Wasserpumpe. Der Schlauch führt durchs Fenster auf den Balkon hinaus.

Weil die Frau des Perlmeisters aber keine mit Heißleim zusammengeflickten Wasserflaschen in der Wohnung duldet, ist das heute vorgestellte Pumpsystem optisch etwas ansprechender: Der Vorratsbehälter besteht aus einem im Haushaltswarenladen gekauften Hundekeksbehälter mit aufklappbarer Öffnung ($4.75) und einer auf Ebay ersteigerten Aquariumpumpe ($6.75 plus Porto). Mit einer Bohrmaschine und einem Schleifkopf wurde auf der Rückseite des Behälters oben ein Spalt hineingefräst, durch den der im Heimwerkermarkt gekaufte Wasserschlauch und das Netzkabel der Pumpe auch bei geschlossenem Deckel nach außen gelangen. Der Schlauch führt durchs Fenster auf den Balkon und endet über den Pflanzentöpfen. Über jeder zu bewässernden Pflanze wurde mit der Bohrmaschine ein kleines Loch in den Schlauch gebohrt, durch das dieser Wasser an die Pflanze abgibt. Es ist darauf zu achten, dass die Löcher nicht zu groß werden, falls doch, kann man sie leicht mit Kleber wieder verkleinern oder ganz zustopfen. Die Aquariumpumpe wurde mit Heißkleber am Behälterboden festgeklebt. Zum Wassernachfüllen klappt man einfach den roten Deckel des Behälters auf.

Abbildung 2: Nicht vergessen: Der Wasservorratsbehälter muss von Zeit zu Zeit nachgefüllt werden.

Gießbefehl durchs Stromnetz

Über ein am Stromnetz hängendes X10-Modul ([3]) wird die Pumpe ein- und ausgeschaltet. Wie schon einmal in [4] vorgestellt, kann man mit dem X10-Protokoll Signale über das Stromnetz schicken. Der Sender hängt in diesem Fall am seriellen (oder USB-) Port des Linux-Rechners und speist mittels einer X10-PC-Schnittstelle (in Deutschland unter anderem auf [5] erhältlich) Signale ins Stromnetz ein. Der Empfängerkasten hängt an einer anderen Steckdose im gleichen Stromnetz und schaltet per Signal die angeschlossene Aquariumpumpe ein und aus.

Abbildung 3: Die Aquariumpumpe wird am X10-Empfänger eingesteckt.

Die Ansteuerung der seriellen Schnittstelle ist ausgesprochen simpel. Das Skript in Listing water muss als root laufen, damit es den Schreibzugriff auf die erste serielle Schnittstelle des Rechners auf /dev/ttyS0 erhält, in die der X10-Sender eingestöpselt wurde. Auch die Steuerung eines Controllers über die USB-Schnittstelle ist übrigens machbar, das wish-Projekt ([6]) stellt die nötige freie Software dafür bereit.

Die im Skript verwendeten Werte für den ``House Code K'' und den ``Unit Code 11'' dienen der Adressierung des Empfängers, der, wie in Abbildung 5 sichtbar, ebenfalls auf ``K'' und ``11'' eingestellt ist. Diese Werte müssen im Hausstromnetz eindeutig sein, sonst kommt es zu Konflikten.

water nutzt die Module Device::SerialPort und ControlX10::CM11 vom CPAN für die Fitzelarbeit mit der seriellen Schnittstelle und den Besonderheiten des X10-Protokolls. Gemäß X10 ist das Kommando zum Einschalten eines Empfängers ``J'', und mit ``K'' wird anschließend wieder abgeschaltet. Vor dem Senden eines Kommandos ist jeweils der Empfänger zu addressieren. Und jedem Kommando geht der ``House Code'' voran.

Listing 1: water

    01 #!/usr/bin/perl
    02 use warnings;
    03 use strict;
    04 
    05 use Device::SerialPort;
    06 use ControlX10::CM11;
    07 use Log::Log4perl qw(:easy);
    08 use Waterscore qw(waterscore);
    09 
    10 my $HOUSE_CODE = "K";
    11 my $UNIT_CODE  = "11";
    12 my $SERIAL     = "/dev/ttyS0";
    13 my $BAUDRATE   = 4800;
    14 my $LOCATION   = "USCA0987";
    15 
    16 die "You must be root" if $> != 0;
    17 
    18 Log::Log4perl->easy_init({
    19   level => $DEBUG, 
    20   file  => ">>/tmp/water.log"});
    21 
    22 my $score = waterscore($LOCATION);
    23 
    24 if($score < 20) {
    25     INFO "No water.";
    26     exit 0;
    27 }
    28 
    29 my $serial = Device::SerialPort->new(
    30     $SERIAL, undef);
    31 $serial->baudrate($BAUDRATE);
    32 
    33   # Address unit
    34 ControlX10::CM11::send($serial, 
    35     $HOUSE_CODE . $UNIT_CODE);
    36 
    37   # Turn water pump on
    38 INFO "Water on";
    39 ControlX10::CM11::send($serial, 
    40     $HOUSE_CODE . "J");
    41 
    42 sleep($score/10);
    43 
    44   # Turn water pump off
    45 INFO "Water off";
    46 ControlX10::CM11::send($serial, 
    47     $HOUSE_CODE . "K");

Grüner Daumen

Balkonpflanzen brauchen bei heißem Wetter mehr Wasser und bei Regen gar keines. Das Skript water kontaktiert deswegen den Wetterservice weather.com auf dem Internet und fragt die aktuelle Temperatur, Luftfeuchtigkeit und die Wetterlage ab. Aus diesen Parametern generiert es einen Bewässerungs-``Score'' von 0 bis 100. Bei 0 brauchen die Pflanzen kein Wasser, bei 100 sehr viel. Bei einem Score von weniger als 20 gießt water deswegen überhaupt nicht und darüber bringen jeweils 10 Punkte eine um eine Sekunde längere Gießdauer. Maximal bleibt die Pumpe also 10 Sekunden an, dieser Wert sollte auf die Pumpkapazität und den Wasserbedarf der Pflanzen auf dem heimischen Balkon abgestimmt werden.

Die Wässerungspunktzahl wird in dem Extra-Modul Waterscore.pm berechnet. Dessen Funktion waterscore wird auf Anweisung des aufrufenden Skripts water in dessen Namensraum exportiert. Perls Exporter-Modul sorgt für diesen Service. Waterscore.pm kontaktiert die Wetterseite weather.com mit einer Partner-ID und einem Lizenzschlüssel, die man dort kostenlos erhält, wenn man sich mit einer gültigen Email-Adresse registriert. Das CPAN-Modul Weather::Com abstrahiert den Zugriff auf den dort angebotenen Webservice und wandelt das zurückkommende XML praktischerweise gleich in Perlstrukturen um.

Listing 2: Waterscore.pm

    01 package Waterscore;
    02 
    03 use base Exporter;
    04 @EXPORT_OK = qw(waterscore);
    05 
    06 use strict;
    07 use warnings;
    08 use Weather::Google;
    09 use Log::Log4perl qw(:easy);
    10 
    11 ###########################################
    12 sub waterscore {
    13 ###########################################
    14   my($loc) = @_;
    15 
    16   my $w = Weather::Google->new(94114);
    17 
    18   # 'icon' => '/images/weather/cloudy.gif',
    19   # 'temp_f' => '95',
    20   # 'temp_c' => '35',
    21   # 'wind_condition' => 'Wind: W at 5 mph',
    22   # 'humidity' => 'Humidity: 42%',
    23   # 'condition' => 'Cloudy'
    24 
    25   my($cond, $temp, $humi) = $w->current('condition', 'temp_c', 'humidity');
    26 
    27   if(!defined $cond) {
    28       ERROR "Failed to get weather from Google";
    29       return undef;
    30   }
    31 
    32   ($humi) = $humi =~ /(\d+)/;
    33   DEBUG "$cond, $temp C, $humi%";
    34 
    35   my $score = 50;
    36   $score += 50 if $humi < 50;
    37   $score -= 30 if $cond =~ /Showers/;
    38   $score -= 80 if $cond =~ /Rain/;
    39   $score += 80 if $cond =~ /Sunny/;
    40 
    41   if($temp > 20) {
    42       $score += ($temp-15)*10;
    43   }
    44 
    45   if($temp < 16) {
    46       $score /= 2.0;
    47   }
    48 
    49   $score = 100 if $score > 100;
    50   $score = 0   if $score < 0;
    51   DEBUG "Score: $score";
    52   return $score;
    53 }
    54 
    55 1;

weather.com liefert das Wetter für Wetterbezirke, die mit Kürzeln wie ``USCA0987'' (für San Francisco) bezeichnet werden. Das Skript location hilft, das Kürzel für den lokalen Wetterbezirk zu finden. Abbildung 4 zeigt die Ausgabe des Skripts mit dem Argument ``berlin''. Neben einer Reihe von ebenfalls ``Berlin'' benannten Städten in den USA liefert es zwei Einträge für das deutsche Berlin. Mit ``München'' kann das Modul sonderbarerweise nichts anfangen, aber mit ``Munich'' aufgerufen liefert es die richtige Wetterstation GMXX0087 der heimlichen Hauptstadt.

Abbildung 4: Die Wetterkürzel für verschiedene Orte mit dem Namen "Berlin".

Listing 3: location

    01 #!/usr/bin/perl -w
    02 use strict;
    03 use Weather::Com;
    04 
    05 my $w = Weather::Com->new();
    06 
    07 $ARGV[0] or die "usage: $0 city";
    08 
    09 my $locs = $w->search($ARGV[0]);
    10 
    11 for my $loc (keys %$locs) {
    12     printf "%-20s %s\n",
    13            $locs->{$loc}, $loc;
    14 }

Waterscore.pm bedient sich einiger empirisch ermittelter Tricks, um den Score zu berechnen. Meldet der Wetterdienst Regen (die Worte "Rain" oder "Showers" kommen im Wetterbericht vor), werden 80 Punkte abgezogen, so dass es kaum Wasser für die Pflanzen geben wird, es sei denn, es ist sehr heiss. Geringe Luftfeuchtigkeit erhöht hingegen die Punktzahl und damit die Gießwahrscheinlichkeit und -dauer. Sonniges Wetter (angezeigt durch das Wort "Sunny" im Feld {cc}->{t}) und Temperaturen über 15 Grad Celsius wirken in ähnlicher Weise auf den Zähler ein.

Wird der Konstruktor von Weather::Com mit einem wahren Wert für den Parameter current aufgerufen, holt die nachher aufgerufene Methode get_weather() die Messwerte für das gerade herrschende Wetter ein. Der auf den Wert "m" (für metrisch) gesetzte Parameter units gibt an, dass die Temperaturen in Celsius (und nicht in Fahrenheit) zurückkommen.

Abbildung 5: Aus einem Loch im Schlauch spritzt Wasser auf die zu bewässernde Balkonpflanze.

Das Modul Waterscore.pm ist so zu installieren, das water es findet (zum Beispiel unter /usr/lib/perl5/site_perl). Ein als root laufender Cronjob mit dem Eintrag

    00 9,16 * * * /usr/bin/water

lässt das Bewässerungsskript zweimal täglich, am Morgen und am Abend, ablaufen und eine angemessene Wassermenge auf die Balkonpflanzen spritzen. Anhand der Logdatei in /tmp/water.log lässt sich jederzeit nachverfolgen, wann wieviel Wasser die Pflanzen benetzt hat. Zu beachten ist, dass der Wasserbehälter genug Wasser auf Vorrat hat, dann steht einem Kurzurlaub nichts im Wege.

Abbildung 6: Die Logdatei listet auf, wann und wieviel Wasser auf die Balkonpflanzen gegossen wurde.

Infos

[1]
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2006/09/Perl

[2]
``Make'', http://makezine.com, Volume 08, Seite 22.

[3]
http://de.wikipedia.org/wiki/X10

[4]
``Kontaktmann'', Michael Schilli, http://www.linux-magazin.de/Artikel/ausgabe/2004/12/perl/perl.html

[5]
http://www.intellihome.be/deutsch/store.asp?pag=cat&menu=7

[6]
http://wish.sourceforge.net

Michael Schilli

arbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com.