Dritter (und letzer) Gehversuch mit Perl, ELV ASH2200 und ELV FS20 WUE

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