Nach allen Irrungen und Wirrungen haben ich nun einen perl Code der einerseits einfach, anderseits auch ziemlich robust sein dürft. Der Trick ist das relativ lange match pattern:
$port->are_match(pack( 'H[18]', '0000000000020ca201' ));
Da ich ja die Sensoren ASH2200 verwende sind die letzten 5 Bytes eines Wetterdatenpaket immer null (Regen, Niederschlag und Windgeschwindigkeit). Da die Wetterdatenpaket immer eine konstante Länge haben, sind auch die ersten 4 Bytes immer konstant auf 020ca201 gesetzt. Nur die nachfolgenden fünf Bytes (Adresse, Temperatur und Luftfeuchtigkeit) enhalten 5 Bytes variable Nutzdaten.
Gerät das ganze mal ausser tritt und das Wetterdatenpaket ist länger oder kürzer, dann wird es einfach ignoriert. Lediglich wenn die variablen Daten exakt 5 Bytes sind wird es dank folgendem Test :
if (defined($c) && (length($c) == 5 )) {
Und hier noch der vollständige perl code incl. Berechnung der absoluten Luftfeuchtigkeit und des Taupunktes:
#! C:\perl\bin\perl.exe
use strict;
use warnings;
use Win32::SerialPort;
my $port = Win32::SerialPort->new("COM5");
sub
af_td ($$)
{
# Formeln von http://www.wettermail.de/wetter/feuchte.html
# r = relative Luftfeuchte
# T = Temperatur in °C
my ($T, $rh) = @_;
# a = 7.5, b = 237.3 für T >= 0
# a = 9.5, b = 265.5 für T < 0 über Eis (Frostpunkt)
my $a = ($T > 0) ? 7.5 : 9.5;
my $b = ($T > 0) ? 237.3 : 265.5;
# SDD = Sättigungsdampfdruck in hPa
# SDD(T) = 6.1078 * 10^((a*T)/(b+T))
my $SDD = 6.1078 * 10**(($a*$T)/($b+$T));
# DD = Dampfdruck in hPa
# DD(r,T) = r/100 * SDD(T)
my $DD = $rh/100 * $SDD;
# AF(r,TK) = 10^5 * mw/R* * DD(r,T)/TK; AF(TD,TK) = 10^5 * mw/R* * SDD(TD)/TK
# R* = 8314.3 J/(kmol*K) (universelle Gaskonstante)
# mw = 18.016 kg (Molekulargewicht des Wasserdampfes)
# TK = Temperatur in Kelvin (TK = T + 273.15)
my $AF = (10**5) * (18.016 / 8314.3) * ($DD / (273.15 + $T));
my $af = sprintf( "%.1f",$AF); # Auf eine Nachkommastelle runden
# TD(r,T) = b*v/(a-v) mit v(r,T) = log10(DD(r,T)/6.1078)
my $v = log10($DD/6.1078);
my $TD = $b*$v/($a-$v);
my $td = sprintf( "%.1f",$TD); # Auf eine Nachkommastelle runden
# TD = Taupunkttemperatur in °C
# AF = absolute Feuchte in g Wasserdampf pro m3 Luft
return($af, $td);
}
sub
log10 {
my $n = shift;
return log($n)/log(10);
}
$port->baudrate(4800);
$port->databits(8);
$port->parity("none");
$port->stopbits(1);
$port->write_settings || undef $port;
$port->write(pack( 'H[08]', '0202fb00' )); #hexmode
$port->write(pack( 'H[08]', '0202f201' )); #Wetterdaten sofort ausgeben
$port->are_match(pack( 'H[18]', '0000000000020ca201' ));
while (1)
{
my $c = $port->lookfor();
if (defined($c) && (length($c) == 5 )) {
my $addr = unpack("H[2]", substr $c, 0, 1) ;
my $temp = unpack('s', pack( 'S', unpack("n", substr $c, 1, 2)))/10;
my $humidity = unpack("n", substr $c, 3, 2)/10;
my ($af, $td) = af_td($temp, $humidity);
print "a: $addr t: $temp h: $humidity af: $af td: $td\n";
}
}
Keine Kommentare:
Kommentar veröffentlichen