ich habe jetzt mal Dein Script aus deinem letzten Post (Link) genommen und angepasst
Code:
#!/usr/bin/perl
# Zaehlerabfrage fuer Zaehler nach Protokoll IEC 62056-21 / OBIS
# Ein Anfrage-Telegramm ist mit 300 Baud, 7 Bit, 1 Stoppbit
# und gerader Paritaet zu senden. Das ist der Initialmodus von Geraeten,
# die das Protokoll IEC 62056-21 implementieren.
# Ein Wechsel der Geschwindigkeit ist möglich, in diesem Script aber noch nicht umgesetzt.
# !!! Wiederholung nur alle 3 Minuten da der Zaehler nach Ende des Scriptes weiter sendet !!!
# Basis des Scripts von volkszaehler.org / Autor: Andreas Schulze & Bugfix: Eric Schanze
# DPT9 sub: makki / www.knx-user-forum.de
# In dieser Version keine Anbindung an den KNX-Bus
# Erweiterung um RRD,KNX-Anbindung und gezielte Wertsuche auf Wiregate:
# JuMi2006 / www.knx-user-forum.de
# Version: 0.1.3
# Datum: 23.04.2012
use warnings;
use strict;
use Device::SerialPort;
use RRDs;
### KONFIGURATION ###
my $device = "/dev/ttyS0"; #Port
my $conf4800 = "/tmp/conf4800"; #temporäre Konfigurationsdatei für Baudwechsel
my $endsign = "!"; #Letztes Zeichen im Protokoll vom Zaehler
my $rrdpath = "/var/www/rrd"; #Pfad für RRDs
my $counterid = "Zaehler_HZ"; #Grundname für RRDs
my %obis=( "16.7"=>6, #Obis-Zahl => Anzahl der Stellen z.B.: 6 = 123.45
"32.7"=>3,
"52.7"=>3,
"31.7"=>6,
"51.7"=>6,
"71.7"=>6,
"72.7"=>3,
"1-0:1.8.1*255"=>10); #!!!COUNTER!!!
my %countermode=("1-0:1.8.1*255"=>24); #Obiscode für Zaehlerstaende
#RRD gibt Verbrauch pro Tag aus (beta)
### ENDE KONFIGURATION ###
### Seriellen Port initialisieren
####4800baud
my $port = new Device::SerialPort($device) || die "can't open $device: $!";
$port->baudrate(9600) || die 'fail setting baudrate';
$port->databits(7) || die 'fail setting databits';
$port->stopbits(1) || die 'fail setting stopbits';
$port->parity("even") || die 'fail setting parity';
$port->rts_active(1);
$port->dtr_active(1);
$port->read_char_time(1000); # 0.5 seconds for each character
$port->read_const_time(5000); # 1 second per unfulfilled "read" call
$port->write_settings || die 'fail write settings';
$port->save($conf4800) || warn "Can't save $conf4800: $!\n";
####START 300baud
$port->baudrate() || die 'fail setting baudrate';
$port->databits(7) || die 'fail setting databits';
$port->stopbits(1) || die 'fail setting stopbits';
$port->parity("even") || die 'fail setting parity';
$port->dtr_active(1);
$port->rts_active(1);
$port->read_char_time(500); # 0.5 seconds for each character
$port->read_const_time(1000); # 1 second per unfulfilled "read" call
$port->write_settings || die 'fail write settings';
### Anforderungstelegramm senden
my $data="2f3f210d0a"; #Anfrage als HEX "/?!<CR><LF>"
my $request = pack('H*',$data);
my $num_out = $port->write($request);
print $request;
die "write failed\n" unless ($num_out);
die "write inclomplete\n" unless ($num_out == length($request));
print "$num_out Bytes written\n";
### Warte auf Zaehlerkennung
select(undef, undef, undef, 1.5); # 1.5 Sekunden warten
### Telegramm mit ACK und neuer Geschwindigkeit senden
my $data2="063030300d0a"; #ACK und neue Geschwindigkeit in HEX "<ACK>040<CR><LF>"
my $baudwechsel = pack('H*',$data2); # 000 = 300baud, 040 = 4800baud
my $num_out2 = $port->write($baudwechsel);
print $baudwechsel;
die "write failed\n" unless ($num_out2);
die "write inclomplete\n" unless ($num_out2 == length($baudwechsel));
print "$num_out2 Bytes written\n";
### Port mit neuer Geschwindigkeit intialisieren
$port->restart($conf4800) || warn "Can't restart $conf4800: $!\n"; ;
#$port->baudrate(300);
#$port->write_settings;
### AUSLESEN
my $STALL_DEFAULT=5; # how many seconds to wait for new input
my $timeout=$STALL_DEFAULT;
my $chars=0;
my $buffer="";
while ($timeout>0) {
my ($count,$saw)=$port->read(25); # Liest 25 Zeichen je Durchlauf aus
if ($count > 0) {
$chars+=$count;
$buffer.=$saw;
#print ($buffer,"\n"); # Ausgabe der eingelesenen Daten
### FILTER FOR END
if ($buffer =~ /\Q$endsign\E/) # \Q \E entwertet alle Sonderzeichen dazwischen
{
$port->close || die "can't close $device: $!"; # Port schlieen
last; # Schleife verlassen
}
### ENDE FILTER FOR END
}
else {
$timeout--;
}
}
if ($timeout<=0) {
$port->close || die "can't close $device: $!";
print "Waited $STALL_DEFAULT seconds and never saw what I wanted\n";
}
print $buffer; #Nur zur Kontrolle
### FILTER FOR DATA
while (my($key, $value) = each %obis)
{
my $obiskey = $key."(";
if ($buffer =~ /\Q$obiskey\E/) # \Q \E entwertet alle Sonderzeichen dazwischen
{
my $pos=index($buffer,$obiskey); # Anfangsposition des OBIS-Key finden
print ("Obiskey: $obiskey","\n"); # Kontrolldruck
print ("Position: $pos","\n"); # Kontrolldruck
print (length($obiskey),"\n"); # Kontrolldruck
my $obisvalue=substr($buffer,($pos+length($key)+1),$obis{$key}); # Wert extrahieren
print ($key,": ",$obisvalue,"\n"); # Kontrolldruck
### RRD-Erstellen
my $obisname = "$key";
$obisname =~ tr/./-/;
my $rrdname = $counterid."_".$obisname."\.rrd";
print ($rrdname,"\n");
my $rrdfile = $rrdpath."\/".$rrdname;
### RRD check COUNTER/GAUGE
if (exists $countermode{$key})
{
print ("COUNTER","\n");
### COUNTER schreiben
unless (-e $rrdfile)
{
RRDs::create ($rrdfile,"DS:value:COUNTER:86500:0:10000000000","RRA:AVERAGE:0.5:1:365","RRA:AVERAGE:0.5:7:300","-s 86400");
}
### RRD-Füllen
RRDs::update("$rrdfile", "N:$obisvalue*=86400");
}
else
{
print ("GAUGE","\n");
###GAUGE schreiben
unless (-e $rrdfile)
{
RRDs::create ($rrdfile,"DS:value:GAUGE:900:0:10000000000","RRA:AVERAGE:0.5:1:2160","RRA:AVERAGE:0.5:5:2016","RRA:AVERAGE:0.5:15:2880","RRA:AVERAGE:0.5:60:8760");
}
### RRD-Füllen
RRDs::update("$rrdfile", "N:$obisvalue");
}
}
}
### ENDE FILTER FOR DATA
### Log der Zaehlerausgabe
#my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
#my $timestamp = printf "%4d-%02d-%02d %02d:%02d:%02d\n",$year+1900,$mon+1,$mday,$hour,$min,$sec;
#open(LOG,'>>',$file) || die "Fehler $!";
#print LOG ("\n",$year+1900,"-",$mon+1,"-",$mday," ",$hour,":",$min,":",$sec," \; ",$value);
#close LOG;
Obiskey: 1-0:1.8.1*255(
Position: 83
14
1-0:1.8.1*255: 000617.072
Zaehler_HZ_1-0:1-8-1*255.rrd
COUNTER
Sieht doch nicht so schlecht aus. Eine Einbindung von GAs zum Senden der Werte hat das ganze ja noch nicht. Ich würde jetzt versuchen die channel Einträge aus dem aktuellen Script
z.B.
Code:
my @channels; #Obis-Zahl => Gruppenadresse
push @channels, {name => "16.7", ga =>"6/3/1", dpt => 9 }; #akt. Leistung
push @channels, {name => "32.7", ga =>"6/3/11", dpt => 9 }; #Spannung L1
push @channels, {name => "52.7", ga =>"6/3/21", dpt => 9 }; #Spannung L2
push @channels, {name => "72.7", ga =>"6/3/31", dpt => 9 }; #Spannung L3
push @channels, {name => "31.7", ga =>"6/3/10", dpt => 9 }; #Stromstaerke L1
push @channels, {name => "51.7", ga =>"6/3/20", dpt => 9 }; #Stromstaerke L2
push @channels, {name => "71.7", ga =>"6/3/30", dpt => 9 }; #Stromstarke L3
push @channels, {name => "1-0:1.8.1", ga =>"6/3/0", dpt => 9 }; #Zaehlerstand gesamt
Grüße,
Mike


Einen Kommentar schreiben: