Wetterstation via RS 485

0

Einbindung der Elsner Wetterstation P03/3-RS485

  • Siemens Logo 24V DC Netzteil
  • Linux Fedora 9
  • eibd
  • php5Diese Kombination mach aus wirtschaftlicher Sicht besonders dann Sinn, wenn man bereits einen 24×7 Linux Server betreibt.

 

Kosten

  • Wetterstation: ca. 350€
  • 24V DC Netzteil: hoffentlich vorhanden
  • Exsys EX-42052: 60€ für 2 Kanäle, d.h. für den benötigten Kanal 30€ (ich hatte diese Karte schon, da am anderen Port mein RS485 Transponder angeschlossen ist)
  • alternativ: RS485-RS232 Konverter 20€

Konfiguration RS485 Schnittstellenkarte

Anschluss Wetterstation
Der Anschluss der Wetterstation hat gemäß Installationanleitung von Elsner zu erfolgen. Dazu ist eine YStY-Leitung 2x2x0,8 ausreichend. Bei mir habe ich eine exklusive EIB Leitung zweckentfremdet, da ich diese für eine EIB Wetterstation bereits am Antennenmast hatte. Dabei war dann folgender Anschluss zu machen:
Klemme 1: 24V+ Klemme 2: 24V- Klemme 3: RS485 Data+ Klemme 4: RS485 Data-
Bitte aber unbedingt in die Beschreibung der Wetterstation schauen, da die Anschlüsse nicht verpolungssicher sind!!! Damit war der Anschluss der Wetterstation bereits fertig und das andere Ende musste noch an den RS485 Port des Linux Server angeschlossen werden.
Die Exsys-Karte hat zwei Terminal Blockanschlüsse, von denen nur die Klemmen 1 und 2 verwendet werden, da es sich um eine Zwei-Draht-RS485 Schnittstelle im halbduplex Betrieb handelt.

Linux Kernel Konfiguration
Der Linux Kernel muss nur den Standard „serial“ Treiber entweder fest oder als Module integriert haben. Bei der Verwendung der Exsys RS485 Schnittstellenkarte kann man nach dem Booten mit „dmesg | grep ttyS“ prüfen, ob die Karte gefunden wurde und welche devices zugeordnet wurden. Da mein Board eine RS232 Schnittstelle hat, werden den beiden RS485 Ports die Devices ttyS1 und ttyS2 zugeordnet:
[CODE][root@david ~]# dmesg | grep ttyS
00:08: ttyS0 at I/O 0x3f8 (irq = 4) is a 16550A
ttyS1: detected caps 00000700 should be 00000100
0000:05:03.0: ttyS1 at I/O 0xd700 (irq = 16) is a 16C950/954
ttyS2: detected caps 00000700 should be 00000100
0000:05:03.0: ttyS2 at I/O 0xd800 (irq = 16) is a 16C950/954[/CODE]

Kommunikationstest mit minicom
Nach dem die Wetterstation nur mit der RS-485 Karte verbunden ist kann getestet werden, ob die Daten empfangen werden können. Ein einfaches Terminalprogramm wie minicom eignet sich hervorragend dazu. Bei der Fedora Linux Distribution kann man ganz einfach sicherstellen, dass minicom intalliert ist. Bei bestehender Internetvebindung sollte dazu folgender Befehl ausreichen:
[CODE]yum install minicom [/CODE]
Entweder wird minicom nun installiert oder man erhält die Meldung, dass es bereits installiert ist. Das kann man natürlich auch prüfen, indem man einfach versucht es zu starten. 😉
Am besten man passt vor dem Start von minicom die /etc/minirc.dfl an, so dass die Werte dort korrekt gesetzt sind. Wie im Datenblatt der Wetterstation nachzulesen sind die Kommunikationsparameter 19200bit/s, 8 Datenbits, ein Stoppbit, keine Parität notwendig. Die Datei /etc/minirc.dfl sollte also folgendes enthalten:
[CODE]pu pname4 NDNYYddddd
pu port /dev/ttyS1
pu baudrate 19200
pu bits 8
pu parity N
pu stopbits 1
[/CODE]
Jetzt kann man mit dem Test beginnen. Dazu startet man einfach minicom mit folgendem Aufruf:
[CODE]minicom -w[/CODE]
Nach dem Start sollten auch schon die Daten der Wetterstation erscheinen und zwar jede Sekunde sollten 39 Byte erscheinen, beginnend mit „W“ und endend mit der Checksumme. So ist es auch im Datenblatt von Elsner beschrieben. Das Stoppbyte 0x03 wird nicht angezeigt, da es sich hierbei um ein nicht darstellbares Zeichen handelt.
Nachdem nun die Daten korrekt an der RS-485 Schnittstelle ankommen, kann jetzt das Mapping auf einen Netzwerk-Socket mit ser2net erfolgen. Dazu mehr im nächsten Abschnitt.

ser2net installieren und konfigurieren
Die Installation von ser2net ist recht einfach. Einfach bei Sourceforge downloaden und entpacken:
[CODE]tar xfvz ser2net-2.5.tar.gz
cd ser2net-2.5
./configure
make
make install
[/CODE]
Danach sollte das ausführbare ser2net im Verzeichnis /usr/local/sbin/ zu finden sein.
Die Konfiguration ist auch nicht komplizierter. Diese erfolgt nämlich komplett über Kommandozeilenparameter beim Start von ser2net. Gemäß der o.g. Feststellung des entsprechenden seriellen Ports wird ser2net mit folgender Syntax gestartet:
[CODE]/usr/local/sbin/ser2net -C „5331:raw:0:/dev/ttyS1:4800 NONE 1STOPBIT 8DATABITS -XONXOFF LOCAL RTSCTS“
[/CODE]Das war’s schon. Damit werden die an der RS-485 Schnittstelle ankommenden Daten der Wetterstation auf einen TCP Socket gemappt, der auf Port 5331 erreichbar ist. ttyS1 bezeichnet hier den COM2: Port und kann je nach Ausstattung des Rechners und Reihenfolge beim Laden der Kernelmodule abweichen. Aber im vorangegangenen Kapitel habe ich ja erläutert wie man den entsprechenden seriellen Port feststellt.
Mehr muss ser2net an dieser Stelle nicht leisten.

Bereitstellung Wetterdaten auf dem KNX-Bus
Mit php lassen sich nun recht einfach Wetterdaten auslesen, weiterverarbeiten und auch auf den KNX senden. Hier ein Beispiel dafür. Den php Code einfach in eine Datei kopieren, speichern, ausführbar machen und starten. Dann werden die Wetterdaten auf dem Bildschirm angezeigt und als Beispiel der Regenindikator als GA 10/10/0 auf den Bus gesendet. Voraussetzungist natürlich, dass der eibd auf dem Rechner installiert ist und dass der darin enthaltene Befehl groupswrite im Verzeichnis /usr/local/bin zu finden ist. Außerdem muss natürlich php installiert sein. Die Sonnenstandsberechnung kann aktiviert werden, indem man die Kommentarzeichen „//“ aus der Zeile
[PHP] // calculate_sun_position($timestamp,$wd);[/PHP]
entfernt und die weiter unten (Erweiterungen) dargestellte Sonnenstandsberechnung mit in die php-Datei integriert. Damit ist dann eine sonnenstandsgeführte Beschattung problemlos implementierbar. Wichtig: Anpassung der Koordinaten in der php Funktion zur Sonnenstandsberechnung. Hier müsst ihr die geographischen Koordinaten eures Hauses eintragen. Kann man sehr einfach in Google Maps herausfinden.
[PHP] #!/usr/bin/php

while (1)
{
$sock = fsockopen(„192.168.0.10″,“5332“); // open socket to ser2net (serial RS485 port)

if ($sock) {
$i=0;

while (!feof($sock))
{
$char = fgetc($sock); // read char from socket
$str[$i] = $char;
if ($str[0]!= „W“) continue; // read and ignore until „W“ received
if ($i < 39) // while less than 39 chars are read
{
$i = ($i+1)%40;
continue; // read next char
}

// build received checksum
$checksum = 1000*$str[35] + 100*$str[36] + 10*$str[37] + $str[38];
// calculating checksum from received data
$sum = 0;
for ($j=0;$j<=34;$j++)
$sum = $sum + ord($str[$j]);
// Verify received checksum against calculated checksum
if ($checksum != $sum) {
echo „Checksum error while receiving data from weather station!\n“;
}
else {
$i = 0; // reset number of received chars

// temperature
$wd[„temperature“> = $str[2]*10+$str[3]+0.1*$str[5];
if ($str[1]==“-„) $wd[„temperature“> *= -1;

// sun south
$wd[„sun_south“> = $str[6]*10+$str[7];

// sun west
$wd[„sun_west“> = $str[8]*10+$str[9];

// sun east
$wd[„sun_east“> = $str[10]*10+$str[11];

// twilight
if ($str[12]==“J“) $wd[„twilight“> = 1; else $wd[„twilight“>=0;

// daylight
$wd[„daylight“> = $str[13]*100+$str[14]*10+$str[15];

// wind
$wd[„wind“> = ($str[16]*10+$str[17]+0.1*$str[19])*3.6;

// Rain
if ($str[20]==“J“) $wd[„rain“> = 1; else $wd[„rain“> = 0;

// date
$wd[„weekday“> = $str[21];
$day = $str[22]*10 + $str[23];
$month = $str[24]*10 + $str[25];
$year = 2000 + $str[26]*10 + $str[27];
$wd[„date“> = $year.“-„.$month.“-„.$day;

// time
$hour = $str[28]*10+$str[29];
$minute = $str[30]*10+$str[31];
$second = $str[32]*10+$str[33];
$wd[„time“> = $hour.“:“.$minute.“:“.$second;

// daylight saving
unset($wd[„daylight_saving“>);
if ($str[34]==“J“) $wd[„daylight_saving“> = 1;
else if ($str[34]==“N“) $wd[„daylight_saving“> = 0;

$timestamp = mktime($hour,$minute,$second,$month,$day,$year);
// calculate_sun_position($timestamp,$wd);
print_r($wd);

// Example to send some weather data on the KNX
// Rain – GA: 10/10/0
$command = „/usr/bin/groupswrite ip:localhost 10/10/0 „.$wd[„rain“>;
exec($command,$output);
if ($output[0]!=“Send request“) echo „ERROR sending data to the KNX: „.$output[0];
unset($output);
}
}
} else echo „Could not open socket 5332“;
}

// Hier wird die Sonnenstandsberechnung reinkopiert

?>
[/PHP]

Erweiterungen

Sonnenstand
Um den Sonnenstand (Azimuth und Elevation) zu berechnen, mss nun einfach die im folgenden dargestellte php Funktion in die bereits vorhandene php-Datei (s.o.) kopiert werden. Man kann sie einfach ans Ende kopieren allerdings vor dem php-Ende Tag ?>.
[PHP]
function calculate_sun_position($timestamp, &$weather_data)
{
// Geographische Koordinaten
$geo_breite = 51.2791456650652;
$geo_laenge = 6.4534592628479;

// Zerlege Datum und Uhrzeit
$monat = intval(gmdate(„n“,$timestamp));
$tag = intval(gmdate(„j“,$timestamp));
$jahr = intval(gmdate(„Y“,$timestamp));
$stunde = intval(gmdate(„G“,$timestamp));
$minute = intval(gmdate(„i“,$timestamp));
$sekunde = intval(gmdate(„s“,$timestamp));

// Berechnungen
$jd12 = gregoriantojd($monat,$tag, $jahr);
$stundenanteil = $stunde >= 12 ? (($stunde)/24+$minute/(60*24)+$sekunde/(60*60*24))-0.5 : (-1*($stunde/24-$minute/(24*60)-$sekunde/(24*60*60)));
$jd12h = $jd12 + $stundenanteil;
$n = $jd12h – 2451545;
$L = 280.460 + 0.9856474 * $n;
$g = 357.528 + 0.9856003 * $n;
$i = intval($L / 360);
$L = $L – $i*360;
$i = intval($g / 360);
$g = $g – $i*360;
$e = 0.0167;
$eL = $L + (2*$e * sin($g/180*M_PI)+ 5/4*$e*$e*sin(2*$g/180*M_PI))*180/pi();
$epsilon = 23.439 – 0.0000004 * $n;
$alpha = atan(cos($epsilon/180*M_PI)*sin($eL/180*M_PI)/cos($eL/180*M_PI))*180/M_PI;

if ((cos($eL/180*M_PI)<0)) $alpha += 180;
$delta = asin(sin($epsilon/180*M_PI)*sin($eL/180*M_PI))*180/M_PI;
$jd0 = $jd12 – 0.5;
$T0 = ($jd0 – 2451545.0) / 36525;
$mittlere_sternzeit_greenwich = 6.697376 + 2400.05134 * $T0 + 1.002738 * ($stunde+$minute/60+$sekunde/3600);
$i = intval($mittlere_sternzeit_greenwich / 24);
$mittlere_sternzeit_greenwich = $mittlere_sternzeit_greenwich – $i*24;
$stundenwinkel_fruehling_greenwich = $mittlere_sternzeit_greenwich * 15;
$stundenwinkel_fruehling = $stundenwinkel_fruehling_greenwich + $geo_laenge;
$stundenwinkel_sonne = $stundenwinkel_fruehling – $alpha;
$nenner = cos($stundenwinkel_sonne/180*M_PI)*sin($geo_breite/180*M_PI)-tan($delta/180*M_PI)*cos($geo_breite/180*M_PI);
$azimut = atan(sin($stundenwinkel_sonne/180*M_PI)/$nenner)*180/M_PI;
if ($nenner<0) $azimut+=180;
if ($azimut>180) $azimut -= 360;
$h = asin(cos($delta/180*M_PI)*cos($stundenwinkel_sonne/180*M_PI)*cos($geo_breite/180*M_PI)+sin($delta/180*M_PI)*sin($geo_breite/180*M_PI))*180/M_PI;
$R = 1.02 / (tan(($h+10.3/($h+5.11))/180*M_PI));
$h_refrak = $h + $R/60;

// Rückgabewerte
$weather_data[„azimuth“> = $azimut;
$weather_data[„elevation“> = $h_refrak;
}[/PHP]