Ankündigung

Einklappen
Keine Ankündigung bisher.

Zählerabfrage als Wiregate Plugin

Einklappen
Dieses Thema ist geschlossen.
X
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • JuMi2006
    antwortet
    Wenn der Zähler wirklich von alleine sendet dann macht das mit dem Script hier keinen Sinn mehr. Dafür hast Du aber schonmal ne gute Vorlage für was eigenes über socat (Webmin->Socketverbindungen).

    Deinem Zähler scheint es egal zu sein ob er aktiv abgefragt wird oder nicht.

    Das '\x2f\x3f\x21\x0d\x0a' durch $device zu ersetzen macht keinen Sinn, hat also nicht zur Datenabfrage beigetragen. Das ist nichts weiter als die in HEX verpackte Abfrageinitialisierung. Da die nicht mehr kommt scheint die Ihm egal zu sein denn er sendet trotzdem.

    Ein Zwitter aus SML und IEC62056 mit 2 Zählerständen

    Ganz ehrlich hier fehlt im Moment die Zeit da richtig drauf einzugehen. Im Kenr würde ich folgendes sagen:

    - Socketverbindung herstellen
    - Plugin machen und auf Socket subscriben
    - im Plugin dann bei ankommenden Daten gucken ob der gesamte Datensatz kommt oder ob socat mal lustig ein par Zeichen ausspuckt
    - Daten ggf. zusammensetzen.
    - Daten verarbeiten

    Sorry aber das ist hier wirklich speziell, ne schnelle Lösung hab ich dafür nicht, bin aber bereit zu helfen.

    Gruß Mirko

    Einen Kommentar schreiben:


  • mikeeyy
    antwortet
    ist der Eintrag korrekt?

    echo '\x2f\x3f\x21\x0d\x0a'

    für den ttyS0 Anschluss?

    habe den echo Eintrag im Code mal wie folgt ersetzt

    Code:
    ### DATEN EMPFANGEN ###
    my @buffer = qx(echo '$device' | socat -T 1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0; sleep 1; echo $ack | socat -T 1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0; socat -T 1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0);
    print @buffer;
    Output jetzt

    'root@wiregate723:/home/user# perl acm2.pl
    9600->'050
    '/ACE5ACE4KGPRS

    0-0:96.1.0*255(05055xxxxxxxxxxxxx)
    1-0:1.8.0*255(002288.902*kWh)
    1-0:1.8.1*255(000436.461*kWh)
    1-0:1.8.2*255(001852.441*kWh)
    1-0:2.8.0*255(000000.226*kWh)
    1-0:2.8.1*255(000000.226*kWh)
    1-0:2.8.2*255(000000.000*kWh)
    0-0:96.14.0*255(02)
    1-0:15.7.0*255(006290*W)
    0-0:17.0.0*255(0085*A)
    0-0:96.3.10*255(1)
    0-1:96.1.0*255(05055yyyyyyyyyyyyy)
    1-1:1.8.0*255(000902.370*kWh)(13-01-02 14:00:09)
    1-1:1.8.1*255(000902.371*kWh)(13-01-02 14:00:09)
    1-1:1.8.2*255(000000.000*kWh)(13-01-02 14:00:09)
    1-1:1.8.3*255(000000.000*kWh)(13-01-02 14:00:09)
    1-1:1.8.4*255(000000.000*kWh)(13-01-02 14:00:09)
    1-1:2.8.0*255(000000.000*kWh)(13-01-02 14:00:09)
    1-1:2.8.1*255(000000.000*kWh)(13-01-02 14:00:09)
    1-1:2.8.2*255(000000.000*kWh)(13-01-02 14:00:09)
    1-1:2.8.3*255(000000.000*kWh)(13-01-02 14:00:09)
    1-1:2.8.4*255(000000.000*kWh)(13-01-02 14:00:09)
    0-1:96.14.0*255(01)(13-01-02 14:00:09)
    1-1:15.7.0*255(000000*W)(13-01-02 14:00:09)
    0-1:17.0.0*255(0000*A)
    0-1:96.3.10*255(1)
    !

    EDIT:
    da der Zähler die Daten selber in Intervallen sendet, muss ich das script ggf. mehrmals ausführen, um den richtigen Zeitpunkt für die Datenerfassung zu erwischen... sonst ist der Output tatsächlich leer..

    Einen Kommentar schreiben:


  • mikeeyy
    antwortet
    da kommt nix...

    ich habe den Teil DATEN EMPFANGEN mal zusammengekürzt, einfach um zu sehen ob überhaupt was ausgelesen werden kann...

    Code:
    ### DATEN EMPFANGEN ###
    my @buffer = qx(echo '\x2f\x3f\x21\x0d\x0a' | socat -T 1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0[SIZE="6"][B])[/B][/SIZE];
    print @buffer;
    Output:

    root@wiregate723:/home/user# perl acm2.pl
    9600->'050
    'root@wiregate723:/home/user#

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Ja sowas müsste man tun ...

    Das hier könnte so klappen, das ist die Vorgängerversion:
    Code:
    use warnings;
    use strict;
    use RRDs;
    
    ### KONFIGURATION ###
    my $device = "/dev/ttyS0"; #Port
    my $rrdpath = "/var/www/rrd"; #Pfad fuer RRDs
    my $counterid = "test"; #Grundname fuer RRDs
    my $baudrate = "9600";			#Baudrate fuer Zaehlerauslesung
    my %channels = ( #Obis-Zahl => Gruppenadresse
    "15.7.0"=>"12/1/1", #akt. Leistung
    "17.0.0"=>"12/1/11", #akt. Stromstärke ?
    "1.8.0"=>"12/1/0" #Zaehlerstand gesamt
    );
    my @countermodes = (5,15,60,1440);	#Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
    
    ### ENDE KONFIGURATION ###
    
    my %speedrate = (			#Je nach Geschwindigkeit andere Befehel an Zaehler senden
    		"300"=>"'\x06\x30\x30\x30\x0d\x0a'",
    		"600"=>"'\x06\x30\x31\x30\x0d\x0a'",
    		"1200"=>"'\x06\x30\x32\x30\x0d\x0a'",
    		"2400"=>"'\x06\x30\x33\x30\x0d\x0a'",
    		"4800"=>"'\x06\x30\x34\x30\x0d\x0a'",
    		"9600"=>"'\x06\x30\x35\x30\x0d\x0a'"
    		);
    		
    my $ack = $speedrate{$baudrate};
    print ($baudrate,"->",$ack);
    
    ### DATEN EMPFANGEN ###
    my @buffer = qx(echo '\x2f\x3f\x21\x0d\x0a' | socat -T 1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0; sleep 1; echo $ack | socat -T 1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0; socat -T 1 - $device,raw,echo=0,b$baudrate,parenb=1,parodd=0,cs7,cstopb=0);
    print @buffer;
    
    foreach (@buffer)
    {
    	foreach my $obis(%channels)
    	{
    	my $obiskey = $obis."\(";
    	if ($_ =~ /\Q$obiskey\E/)
    	{
    	$_  =~ m/[^(]+\(([^*]+)\*([^)]+)/;
    	my $value = $1;
    	my $unit = $2;
    	my $ga = $channels{$obis};
    	print ($obis,"\n");
    	print ($value,"\n");
    	print ($unit,"\n");
    	print ($ga,"\n");
    	if ($unit =~ /\Qh\E/)
    	{
    	&rrd_counter ($obis,$value)
    	}
    	else
    	{
    	&rrd_gauge ($obis,$value)
    	}
    	&knx_write ($ga,$value);
    	}
    	}
    }
    
    ### SUBS ###
    
    sub rrd_counter
    {
    print ("COUNTER","\n");
    foreach (@countermodes)
    {
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."_".$_."\.rrd";
    print ($rrdname,"\n");
    my $rrdfile = $rrdpath."\/".$rrdname;
    unless (-e $rrdfile)
    {
    RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:10000000000","RRA:AVERAGE:0.5:1:365","RRA:AVERAGE:0.5:7:300","-s ".($_*60));
    }
    my $countervalue = int($value*$_*60);
    RRDs::update("$rrdfile", "N:$countervalue");
    }
    }
    
    sub rrd_gauge
    {
    print ("GAUGE","\n");
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."\.rrd";
    print ($rrdname,"\n");
    my $rrdfile = $rrdpath."\/".$rrdname;
    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");
    }
    RRDs::update("$rrdfile", "N:$value");
    }
    
    sub knx_write
    {
    ### Wert in DPT9 umwandeln und in Konsole ausgeben
    my @hexdec = encode_dpt9($_[1]);
    my $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]);
    print ($hexval,"\n");
    system("groupwrite ip:localhost $_[0] $hexval");
    }
    
    sub encode_dpt9 
    {
    # 2byte signed float
    my $state = shift;
    my $data;
    my $sign = ($state <0 ? 0x8000 : 0);
    my $exp  = 0;
    my $mant = 0;
    $mant = int($state * 100.0);
    while (abs($mant) > 2047)
    {
    $mant /= 2;
    $exp++;
    }
    $data = $sign | ($exp << 11) | ($mant & 0x07ff);
    return $data >> 8, $data & 0xff;
    }

    Einen Kommentar schreiben:


  • mikeeyy
    antwortet
    hier mein aktuelles init.pl script

    Code:
    #!/usr/bin/perl
    use warnings;
    use strict;
    use Device::SerialPort;
    
    ### KONFIGURATION ###
    my $device = "/dev/ttyS0";	#Port
    my $endsign = "!";				#Letztes Zeichen im Protokoll vom Zaehler
    ### ENDE KONFIGURATION ###
    
    ### Seriellen Port initialisieren
    
    ####START 300baud
    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->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";
    
    ### 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

    Hinsichtlich der Trennung der beiden Zähler...

    Die Infos von Zähler eins beginnen mit 1-0:

    1-0:1.8.0*255(002281.998*kWh)
    1-0:1.8.1*255(000436.461*kWh)
    1-0:1.8.2*255(001845.537*kWh)
    1-0:2.8.0*255(000000.226*kWh)
    1-0:2.8.1*255(000000.226*kWh)
    1-0:2.8.2*255(000000.000*kWh)

    Die von Zähler zwei mit 1-1:

    1-1:1.8.0*255(000902.070*kWh)(13-01-02 12:00:06)

    ich würde mir (naiv) folgende Lösung vorstellen. Für die Aufbereitung der Charts muss ich ja eh wissen welcher Zähler für was ist (Hausstrom oder WP). Das müsste ich also im Script hinterlegen. Zähler eins (Hausstrom) hätte damit die idZ=0, Zähler (WP) zwei die idZ=1. Es werden gesamt also zwei Zähler hinterlegt. Wenn mehrere Zähler im Script eingebunden werden, müssten zwei Zählerstände ausgelesen und verarbeitet werden. Das Script liest also im Zähler Output 1-id:1.8.0 und fängt mit id=0 an. Das ganze kann ich vielleicht in Form einer Schleife erfolgen..
    id=0
    if id<idZ then auslesen von 1-id:1.8.0
    id=id+1
    return

    das ganze wird so lange gemacht bis id=idZ und damit alle Zähler erschlagen sind. abhängig von vom wert von id wird ein extra chart erstellt.

    Soweit meine Theorie :-)

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Zitat von mikeeyy Beitrag anzeigen
    Hallo JuMi,

    in Deinem Code haben sich ein paar Fehler (Leerzeichen) bei den socat Zeilen eingeschlichen. Habe ich bereinigt. Code sieht jetzt so aus:
    Ja ich hatte aus dem Forum kopiert, da passiert sowas eben wenn man es nicht sauber als CODE taggt.

    Zitat von mikeeyy Beitrag anzeigen
    root@wiregate723:/home/user# perl acm1.pl
    substr outside of string at acm1.pl line 65.
    root@wiregate723:/home/user#
    O.K. da weiß ich wo der Fehler liegt, sollte aber trotzdem weiter durchlaufen.

    Zitat von mikeeyy Beitrag anzeigen
    Und Du hast Recht. Es handelt sich um zwei Zähler. Einer für den Hausstrom und einer für die Wärmepumpe. Wobei der Hausstromzähler via internem Zähler Bus an den WP Zähler angebunden ist, da dieser die Daten via GPRS an meine Stadtwerke sendet.
    Das wird hässlich!

    Zitat von mikeeyy Beitrag anzeigen
    das init.pl script läuft stabil. kann ich beliebig starten und das läuft sauber durch.
    Bitte einmal posten, dann kann ich darauf basierend mal eine Revision vorher vllt. was machen.


    Was mir noch nicht klar ist wie man die 2-in-1 Zählergeschichte vernünftig trennt.


    Gruß

    Einen Kommentar schreiben:


  • mikeeyy
    antwortet
    Hallo JuMi,

    in Deinem Code haben sich ein paar Fehler (Leerzeichen) bei den socat Zeilen eingeschlichen. Habe ich bereinigt. Code sieht jetzt so aus:

    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 umgesetzt.
    # Basis des Scripts von volkszaehler.org / Autor: Andreas Schulze & Bugfix: Eric Schanze
    # DPT9 sub: makki / www.knx-user-forum.de
    # Baudwechsel: panzaeron / www.knx-user-forum.de
    # Erweiterung um RRD,KNX-Anbindung und gezielte Wertsuche auf Wiregate: 
    # JuMi2006 / www.knx-user-forum.de
    # Version: 0.1.6
    # Datum: 16.08.2012
    
    use warnings;
    use strict;
    use RRDs;
    
    ### KONFIGURATION ###
    
    my $device = "/dev/ttyS0"; #Port
    my $rrdpath = "/var/www/rrd"; #Pfad fuer RRDs
    my $counterid = "test"; #Grundname fuer RRDs
    my $baudrate = 9600; #Baudrate fuer Zaehlerauslesung "auto" oder 300,600,etc
    my %channels = ( #Obis-Zahl => Gruppenadresse
    "15.7.0"=>"12/1/1", #akt. Leistung
    "17.0.0"=>"12/1/11", #akt. Stromstärke ?
    "1.8.0"=>"12/1/0" #Zaehlerstand gesamt
    );
    my @countermodes = (5,15,60,1440); #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
    my $debug = 0;
    
    ### ENDE KONFIGURATION ###
    #Je nach Geschwindigkeit andere Befehle an Zaehler senden
    
    my %speedrate = ( 
    "300"=>"'\x06\x30\x30\x30\x0d\x0a'",
    "600"=>"'\x06\x30\x31\x30\x0d\x0a'",
    "1200"=>"'\x06\x30\x32\x30\x0d\x0a'",
    "2400"=>"'\x06\x30\x33\x30\x0d\x0a'",
    "4800"=>"'\x06\x30\x34\x30\x0d\x0a'",
    "9600"=>"'\x06\x30\x35\x30\x0d\x0a'"
    );
    my %speedrate_auto = ( 
    "0"=>"'\x06\x30\x30\x30\x0d\x0a'",
    "1"=>"'\x06\x30\x31\x30\x0d\x0a'",
    "2"=>"'\x06\x30\x32\x30\x0d\x0a'",
    "3"=>"'\x06\x30\x33\x30\x0d\x0a'",
    "4"=>"'\x06\x30\x34\x30\x0d\x0a'",
    "5"=>"'\x06\x30\x35\x30\x0d\x0a'"
    );
    my %baud = ( 
    "0"=>"300",
    "1"=>"600",
    "2"=>"1200",
    "3"=>"2400",
    "4"=>"4800",
    "5"=>"9600"
    );
    
    ### DATEN EMPFANGEN ###
    
    ### Anfrage Senden ###
    my $id = qx(echo '\x2f\x3f\x21\x0d\x0a' | socat -T1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0);
    my $speedcode = substr($id,4,1);
    my $ack = $speedrate{$baudrate};
    
    ### Zählerkennung auswerten - Geschwindigkeit ermitteln ###
    if ($baudrate eq "auto")
    {
    $ack = $speedrate_auto{$speedcode};
    $baudrate = $baud{$speedcode};
    }
    else
    {
    $ack = $speedrate{$baudrate};
    }
    
    if ($debug==1){print ($id,"\n")};
    if ($debug==1){print ($baudrate,"\n")};
    
    select(undef, undef, undef, 1); 
    ### Abfrage starten ###
    my @buffer = qx(echo $ack | socat -t1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0; socat -T 1 - $device,raw,echo=0,b$baudrate,parenb=1,parodd=0,cs7,cstopb=0 );
    if ($debug==1){print (@buffer,"\n")};
    ### AUSWERTUNG ###
    foreach (@buffer)
    {
    foreach my $obis(%channels)
    {
    my $obiskey = $obis."\(";
    if ($_ =~ /\Q$obiskey\E/)
    {
    $_ =~ m/[^(]+\(([^*]+)\*([^)]+)/;
    my $value = $1;
    my $unit = $2;
    my $ga = $channels{$obis};
    if ($debug==1){print ($obis,"\n")};
    if ($debug==1){print ($value,"\n")};
    if ($debug==1){print ($unit,"\n")};
    if ($debug==1){print ($ga,"\n")};
    if ($unit =~ /\Qh\E/)
    {
    &rrd_counter ($obis,$value)
    }
    else
    {
    &rrd_gauge ($obis,$value)
    }
    &knx_write ($ga,$value);
    }
    }
    }
    
    ### SUBS ###
    
    sub rrd_counter
    {
    if ($debug==1){print ("COUNTER","\n")};
    foreach (@countermodes)
    {
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."_".$_."\.rrd";
    if ($debug==1){print ($rrdname,"\n")};
    my $rrdfile = $rrdpath."\/".$rrdname;
    unless (-e $rrdfile)
    {
    RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:10 000000000","RRA:AVERAGE:0.5:1:365","RRA:AVERAGE:0. 5:7:300","-s ".($_*60));
    }
    my $countervalue = int($value*$_*60);
    RRDs::update("$rrdfile", "N:$countervalue");
    }
    }
    
    sub rrd_gauge
    {
    if ($debug==1){print ("GAUGE","\n")};
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."\.rrd";
    if ($debug==1){print ($rrdname,"\n")};
    my $rrdfile = $rrdpath."\/".$rrdname;
    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");
    }
    RRDs::update("$rrdfile", "N:$value");
    }
    
    sub knx_write
    {
    ### Wert in DPT9 umwandeln und in Konsole ausgeben
    my @hexdec = encode_dpt9($_[1]);
    my $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]);
    #print ($hexval,"\n");
    system("groupwrite ip:localhost $_[0] $hexval");
    }
    
    sub encode_dpt9 
    {
    # 2byte signed float
    my $state = shift;
    my $data;
    my $sign = ($state <0 ? 0x8000 : 0);
    my $exp = 0;
    my $mant = 0;
    $mant = int($state * 100.0);
    while (abs($mant) > 2047)
    {
    $mant /= 2;
    $exp++;
    }
    $data = $sign | ($exp << 11) | ($mant & 0x07ff);
    return $data >> 8, $data & 0xff;
    }
    und der Output so:

    root@wiregate723:/home/user# perl acm1.pl
    substr outside of string at acm1.pl line 65.
    root@wiregate723:/home/user#


    unter /var/www/rrd ist auch nichts neues zu finden.

    Und Du hast Recht. Es handelt sich um zwei Zähler. Einer für den Hausstrom und einer für die Wärmepumpe. Wobei der Hausstromzähler via internem Zähler Bus an den WP Zähler angebunden ist, da dieser die Daten via GPRS an meine Stadtwerke sendet.

    EDIT:
    das init.pl script läuft stabil. kann ich beliebig starten und das läuft sauber durch.


    Grüße,
    Mike

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Hallo Mike,

    sei so Gut und pack das in Code-Tags (das Symbol mit der Raute) das liest sich einfach besser.
    Ein Problem ist mir gestern Abend noch aufgefallen, Dein Zähler fragt mehrere Werte ab oder? Du hast z.B. die 1.8.0 zweimal mit unterschiedlichen Ständen, das wird hier ohne Codeänderung sicherlich zu Problemen führen.

    Wie zuverlässig arbeitet denn das init.pl?

    Als Code probiere mal das hier:
    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 umgesetzt.
    # Basis des Scripts von volkszaehler.org / Autor: Andreas Schulze & Bugfix: Eric Schanze
    # DPT9 sub: makki / www.knx-user-forum.de
    # Baudwechsel: panzaeron / www.knx-user-forum.de
    # Erweiterung um RRD,KNX-Anbindung und gezielte Wertsuche auf Wiregate: 
    # JuMi2006 / www.knx-user-forum.de
    # Version: 0.1.6
    # Datum: 16.08.2012
    
    use warnings;
    use strict;
    use RRDs;
    
    ### KONFIGURATION ###
    
    my $device = "/dev/ttyS0"; #Port
    my $rrdpath = "/var/www/rrd"; #Pfad fuer RRDs
    my $counterid = "test"; #Grundname fuer RRDs
    my $baudrate = 9600; #Baudrate fuer Zaehlerauslesung "auto" oder 300,600,etc
    my %channels = ( #Obis-Zahl => Gruppenadresse
    "15.7.0"=>"12/1/1", #akt. Leistung
    "17.0.0"=>"12/1/11", #akt. Stromstärke ?
    "1.8.0"=>"12/1/0" #Zaehlerstand gesamt
    );
    my @countermodes = (5,15,60,1440); #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
    my $debug = 0;
    
    ### ENDE KONFIGURATION ###
    #Je nach Geschwindigkeit andere Befehle an Zaehler senden
    
    my %speedrate = ( 
    "300"=>"'\x06\x30\x30\x30\x0d\x0a'",
    "600"=>"'\x06\x30\x31\x30\x0d\x0a'",
    "1200"=>"'\x06\x30\x32\x30\x0d\x0a'",
    "2400"=>"'\x06\x30\x33\x30\x0d\x0a'",
    "4800"=>"'\x06\x30\x34\x30\x0d\x0a'",
    "9600"=>"'\x06\x30\x35\x30\x0d\x0a'"
    );
    my %speedrate_auto = ( 
    "0"=>"'\x06\x30\x30\x30\x0d\x0a'",
    "1"=>"'\x06\x30\x31\x30\x0d\x0a'",
    "2"=>"'\x06\x30\x32\x30\x0d\x0a'",
    "3"=>"'\x06\x30\x33\x30\x0d\x0a'",
    "4"=>"'\x06\x30\x34\x30\x0d\x0a'",
    "5"=>"'\x06\x30\x35\x30\x0d\x0a'"
    );
    my %baud = ( 
    "0"=>"300",
    "1"=>"600",
    "2"=>"1200",
    "3"=>"2400",
    "4"=>"4800",
    "5"=>"9600"
    );
    
    ### DATEN EMPFANGEN ###
    
    ### Anfrage Senden ###
    my $id = qx(echo '\x2f\x3f\x21\x0d\x0a' | socat -T1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,csto pb=0);
    my $speedcode = substr($id,4,1);
    my $ack = $speedrate{$baudrate};
    
    ### Zählerkennung auswerten - Geschwindigkeit ermitteln ###
    if ($baudrate eq "auto")
    {
    $ack = $speedrate_auto{$speedcode};
    $baudrate = $baud{$speedcode};
    }
    else
    {
    $ack = $speedrate{$baudrate};
    }
    
    if ($debug==1){print ($id,"\n")};
    if ($debug==1){print ($baudrate,"\n")};
    
    select(undef, undef, undef, 1); 
    ### Abfrage starten ###
    my @buffer = qx(echo $ack | socat -t1 - $device,raw,echo=0,b9600,parenb=1,parodd=0,cs7,csto pb=0; socat -T 1 - $device,raw,echo=0,b$baudrate,parenb=1,parodd=0,cs 7,cstopb=0 );
    if ($debug==1){print (@buffer,"\n")};
    ### AUSWERTUNG ###
    foreach (@buffer)
    {
    foreach my $obis(%channels)
    {
    my $obiskey = $obis."\(";
    if ($_ =~ /\Q$obiskey\E/)
    {
    $_ =~ m/[^(]+\(([^*]+)\*([^)]+)/;
    my $value = $1;
    my $unit = $2;
    my $ga = $channels{$obis};
    if ($debug==1){print ($obis,"\n")};
    if ($debug==1){print ($value,"\n")};
    if ($debug==1){print ($unit,"\n")};
    if ($debug==1){print ($ga,"\n")};
    if ($unit =~ /\Qh\E/)
    {
    &rrd_counter ($obis,$value)
    }
    else
    {
    &rrd_gauge ($obis,$value)
    }
    &knx_write ($ga,$value);
    }
    }
    }
    
    ### SUBS ###
    
    sub rrd_counter
    {
    if ($debug==1){print ("COUNTER","\n")};
    foreach (@countermodes)
    {
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."_".$_."\.rrd";
    if ($debug==1){print ($rrdname,"\n")};
    my $rrdfile = $rrdpath."\/".$rrdname;
    unless (-e $rrdfile)
    {
    RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:10 000000000","RRA:AVERAGE:0.5:1:365","RRA:AVERAGE:0. 5:7:300","-s ".($_*60));
    }
    my $countervalue = int($value*$_*60);
    RRDs::update("$rrdfile", "N:$countervalue");
    }
    }
    
    sub rrd_gauge
    {
    if ($debug==1){print ("GAUGE","\n")};
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."\.rrd";
    if ($debug==1){print ($rrdname,"\n")};
    my $rrdfile = $rrdpath."\/".$rrdname;
    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");
    }
    RRDs::update("$rrdfile", "N:$value");
    }
    
    sub knx_write
    {
    ### Wert in DPT9 umwandeln und in Konsole ausgeben
    my @hexdec = encode_dpt9($_[1]);
    my $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]);
    #print ($hexval,"\n");
    system("groupwrite ip:localhost $_[0] $hexval");
    }
    
    sub encode_dpt9 
    {
    # 2byte signed float
    my $state = shift;
    my $data;
    my $sign = ($state <0 ? 0x8000 : 0);
    my $exp = 0;
    my $mant = 0;
    $mant = int($state * 100.0);
    while (abs($mant) > 2047)
    {
    $mant /= 2;
    $exp++;
    }
    $data = $sign | ($exp << 11) | ($mant & 0x07ff);
    return $data >> 8, $data & 0xff;
    }

    Einen Kommentar schreiben:


  • mikeeyy
    antwortet
    Hier meine aktuell genutzte Version. Dabei handelt es sich um die SVN Version, welche entsprechend den vorherigen Posts angepasst wurde


    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 umgesetzt.
    # Basis des Scripts von volkszaehler.org / Autor: Andreas Schulze & Bugfix: Eric Schanze
    # DPT9 sub: makki / [URL="http://www.knx-user-forum.de"]www.knx-user-forum.de[/URL]
    # Baudwechsel: panzaeron / [URL="http://www.knx-user-forum.de"]www.knx-user-forum.de[/URL]
    # Erweiterung um RRD,KNX-Anbindung und gezielte Wertsuche auf Wiregate: 
    # JuMi2006 / [URL="http://www.knx-user-forum.de"]www.knx-user-forum.de[/URL]
    # Version: 0.1.6
    # Datum: 16.08.2012
    
    use warnings;
    use strict;
    use RRDs;
    
    ### KONFIGURATION ###
    
    my $device = "/dev/ttyS0";    #Port
    my $rrdpath = "/var/www/rrd";        #Pfad fuer RRDs
    my $counterid = "test";            #Grundname fuer RRDs
    my $baudrate = 9600;            #Baudrate fuer Zaehlerauslesung "auto" oder 300,600,etc
    my %channels = (            #Obis-Zahl => Gruppenadresse
            "16.7"=>"12/1/1",    #akt. Leistung
            "32.7"=>"12/1/11",    #Spannung L1
            "52.7"=>"12/1/21",    #Spannung L2
            "31.7"=>"12/1/10",    #Stromstaerke L1
            "51.7"=>"12/1/20",    #Stromstaerke L2
            "71.7"=>"12/1/30",    #Stromstarke L3
            "72.7"=>"12/1/32",    #Spannung L3
            "1-0:1.8.0"=>"12/1/0"    #Zaehlerstand gesamt
                    );
    my @countermodes = (5,15,60,1440);    #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
    my $debug = 0;
    
    ### ENDE KONFIGURATION ###
    #Je nach Geschwindigkeit andere Befehle an Zaehler senden
    
    my %speedrate = (            
            "300"=>"'\x06\x30\x30\x30\x0d\x0a'",
            "600"=>"'\x06\x30\x31\x30\x0d\x0a'",
            "1200"=>"'\x06\x30\x32\x30\x0d\x0a'",
            "2400"=>"'\x06\x30\x33\x30\x0d\x0a'",
            "4800"=>"'\x06\x30\x34\x30\x0d\x0a'",
            "9600"=>"'\x06\x30\x35\x30\x0d\x0a'"
            );
    my %speedrate_auto = (            
            "0"=>"'\x06\x30\x30\x30\x0d\x0a'",
            "1"=>"'\x06\x30\x31\x30\x0d\x0a'",
            "2"=>"'\x06\x30\x32\x30\x0d\x0a'",
            "3"=>"'\x06\x30\x33\x30\x0d\x0a'",
            "4"=>"'\x06\x30\x34\x30\x0d\x0a'",
            "5"=>"'\x06\x30\x35\x30\x0d\x0a'"
            );
    my %baud = (            
            "0"=>"300",
            "1"=>"600",
            "2"=>"1200",
            "3"=>"2400",
            "4"=>"4800",
            "5"=>"9600"
            );
    
    ### DATEN EMPFANGEN ###
    
    ### Anfrage Senden ###
    my $id = qx(echo '\x2f\x3f\x21\x0d\x0a' | socat -T1 - $device,raw,echo=0,b300,parenb=1,parodd=0,cs7,cstopb=0);
    my $speedcode =  substr($id,4,1);
    my $ack = $speedrate{$baudrate};
    
    ### Zählerkennung auswerten - Geschwindigkeit ermitteln ###
    if ($baudrate eq "auto")
    {
    $ack = $speedrate_auto{$speedcode};
    $baudrate = $baud{$speedcode};
    }
    else
    {
    $ack = $speedrate{$baudrate};
    }
    
    if ($debug==1){print ($id,"\n")};
    if ($debug==1){print ($baudrate,"\n")};
    
    select(undef, undef, undef, 1); 
    ### Abfrage starten ###
    my @buffer = qx(echo $ack | socat -t1 - $device,raw,echo=0,b300,parenb=1,parodd=0,cs7,cstopb=0; socat -T 1 - $device,raw,echo=0,b$baudrate,parenb=1,parodd=0,cs7,cstopb=0 );
    if ($debug==1){print (@buffer,"\n")};
    ### AUSWERTUNG ###
    foreach (@buffer)
    {
        foreach my $obis(%channels)
        {
        my $obiskey = $obis."\(";
        if ($_ =~ /\Q$obiskey\E/)
        {
        $_  =~ m/[^(]+\(([^*]+)\*([^)]+)/;
        my $value = $1;
        my $unit = $2;
        my $ga = $channels{$obis};
        if ($debug==1){print ($obis,"\n")};
        if ($debug==1){print ($value,"\n")};
        if ($debug==1){print ($unit,"\n")};
        if ($debug==1){print ($ga,"\n")};
        if ($unit =~ /\Qh\E/)
        {
        &rrd_counter ($obis,$value)
        }
        else
        {
        &rrd_gauge ($obis,$value)
        }
        &knx_write ($ga,$value);
        }
        }
    }
    
    ### SUBS ###
    
    sub rrd_counter
    {
    if ($debug==1){print ("COUNTER","\n")};
    foreach (@countermodes)
    {
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."_".$_."\.rrd";
    if ($debug==1){print ($rrdname,"\n")};
    my $rrdfile = $rrdpath."\/".$rrdname;
    unless (-e $rrdfile)
    {
    RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:10000000000","RRA:AVERAGE:0.5:1:365","RRA:AVERAGE:0.5:7:300","-s ".($_*60));
    }
    my $countervalue = int($value*$_*60);
    RRDs::update("$rrdfile", "N:$countervalue");
    }
    }
    
    sub rrd_gauge
    {
    if ($debug==1){print ("GAUGE","\n")};
    my $obisname = $_[0];
    my $value = $_[1];
    $obisname =~ tr/./-/;
    my $rrdname = $counterid."_".$obisname."\.rrd";
    if ($debug==1){print ($rrdname,"\n")};
    my $rrdfile = $rrdpath."\/".$rrdname;
    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");
    }
    RRDs::update("$rrdfile", "N:$value");
    }
    
    sub knx_write
    {
    ### Wert in DPT9 umwandeln und in Konsole ausgeben
    my @hexdec = encode_dpt9($_[1]);
    my $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]);
    #print ($hexval,"\n");
    system("groupwrite ip:localhost $_[0] $hexval");
    }
    
    sub encode_dpt9 
    {
    # 2byte signed float
    my $state = shift;
    my $data;
    my $sign = ($state <0 ? 0x8000 : 0);
    my $exp  = 0;
    my $mant = 0;
    $mant = int($state * 100.0);
    while (abs($mant) > 2047)
    {
    $mant /= 2;
    $exp++;
    }
    $data = $sign | ($exp << 11) | ($mant & 0x07ff);
    return $data >> 8, $data & 0xff;
    }



    Grüße,
    Mike

    Einen Kommentar schreiben:


  • makki
    antwortet
    Zitat von JuMi2006 Beitrag anzeigen
    Herrlich ...ja wozu gibt es denn Normen bitteschön? Bei sowas könnt ich ko**** ... genau wie meine blöde ..
    Jaja, so ist das leider.. Auch wenn ich gerne über KNX mosere; da klopft jemand auf die Finger und guckt das auch was zusammenpasst

    Mein Zähler hat nur klich-klack (evtl. einfacher?) aber wenn was zum packen gibt-> insistieren

    Makki

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Poste mal das ganze script.
    Besser vielleicht gleich eine Revision vorher aus dem SVN nehmen. Vielleicht reicht es dort überall die 300 baud gegen 9600 baud auszutauschen. Das sollte nur in 2 Zeilen der Fall sein die die socat Abfrage machen.

    Gruß

    Einen Kommentar schreiben:


  • mikeeyy
    antwortet
    Ok.. jetzt habe ich im eigentlichen Zähler Script den Eintrag angepasst an

    my $baudrate = 9600;

    da passiert jetzt aber auch nicht viel mehr. output hier:

    root@wiregate723:/home/user# perl acm.pl
    substr outside of string at acm.pl line 70.
    root@wiregate723:/home/user

    unter /var/www/rrd gibt es auch keine weiteren RRDs

    EDIT:

    den Eintrag %channels habe ich angepasst

    "1-0:1.8.0"=>"12/1/0" #Zaehlerstand gesamt

    Einen Kommentar schreiben:


  • Northman
    antwortet
    Zitat von mikeeyy Beitrag anzeigen
    Sieht doch schon besser aus...
    ...und erklärt, warum Hyperterminal gereicht hat :-)
    Wenn keine Umschaltung der Geschwindigkeit nötig ist und die Werte als Klartext kommen, funktioniert sogar diese Uraltsoftware :-)

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Kannste abbrechen da kommt wohl nix mehr.

    Schwer zu sagen was die sich da ausgedacht haben. Im ersten Satz entspricht die Kommunikation dem 62056 und im nächsten distanziert man sich davon.

    Neben der Geschwindigkeit beim Port muss der zweite gesendete Befehl womöglich auch 040 sein statt 000 bzw. im script glaub ich 0x30 0x30 0x30 auf
    0x30 0x35 0x30 geändert werden.

    Ansonsten muss sich der Hersteller da mal äussern.

    EDIT: Na geht doch

    Einen Kommentar schreiben:


  • mikeeyy
    antwortet
    :-)




    root@wiregate723:/home/user# perl init.pl
    /?!
    5 Bytes written
    000
    6 Bytes written
    /ACE5ACE4KGPRS

    0-0:96.1.0*255(xxxxxxxxxxxxxxxxxxxxxxx)
    1-0:1.8.0*255(002240.945*kWh)
    1-0:1.8.1*255(000423.315*kWh)
    1-0:1.8.2*255(001817.630*kWh)
    1-0:2.8.0*255(000000.226*kWh)
    1-0:2.8.1*255(000000.226*kWh)
    1-0:2.8.2*255(000000.000*kWh)
    0-0:96.14.0*255(02)
    1-0:15.7.0*255(000000*W)
    0-0:17.0.0*255(0085*A)
    0-0:96.3.10*255(1)
    0-1:96.1.0*255(yyyyyyyyyyyyyyyyyyyyyyyyyyy)
    1-1:1.8.0*255(000899.825*kWh)(13-01-01 21:01:08)
    1-1:1.8.1*255(000899.826*kWh)(13-01-01 21:01:08)
    1-1:1.8.2*255(000000.000*kWh)(13-01-01 21:01:08)
    1-1:1.8.3*255(000000.000*kWh)(13-01-01 21:01:08)
    1-1:1.8.4*255(000000.000*kWh)(13-01-01 21:01:08)
    1-1:2.8.0*255(000000.000*kWh)(13-01-01 21:01:08)
    1-1:2.8.1*255(000000.000*kWh)(13-01-01 21:01:08)
    1-1:2.8.2*255(000000.000*kWh)(13-01-01 21:01:08)
    1-1:2.8.3*255(000000.000*kWh)(13-01-01 21:01:08)
    1-1:2.8.4*255(000000.000*kWh)(13-01-01 21:01:08)
    0-1:96.14.0*255(01)(13-01-01 21:01:08)
    1-1:15.7.0*255(000000*W)(13-01-01 21:01:08)
    0-1:17.0.0*255(0000*A)
    0-1:96.3.10*255(1)
    !


    Sieht doch schon besser aus...

    Einen Kommentar schreiben:

Lädt...
X