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

  • mosjka1
    antwortet
    Zitat von coolrunnings Beitrag anzeigen
    Alle 5 Minuten.



    Das sieht gut aus. Wie gesagt, du kannst die COUNTER RRDs noch deaktivieren. Einfach
    Code:
    @countermodes =();
    Sieht auch soweit schlüssig aus. Aber 19,6W momentaner Verbrauch ist schon sportlich. Hast du noch nichts dran hängen?



    Die würde ich noch aus der Config entfernen.
    flutsch jetzt bestens!!! Danke !!!

    Ps.: der Lesekopf hängt an dem Zähler von der Luftwärmepumpe. Sie war gerade nicht im Betrieb. Wenn sie mal anläuft, sieht die Sache ganz anders aus, leider!

    Wenn ich noch einen zweiten Lesekopf an den Haustromzähler dran machen möchte, erstelle ich dazu eine Kopie von diesem script und dort ändere ich die Schnittstelle ab, oder kann der zweite Zähler über den selben script laufen. Die Zähler sind identisch.

    Einen Kommentar schreiben:


  • kleinklausi
    antwortet
    Entschuldigt, dass ich mich hier dran hänge.
    Ich habe zwei Leseköpfe von Udo an zwei EMH Zählern, die am Wiregate hängen. Ich habe extra ein 3.5.1-wiregate-1.41 Kernel installiert (installieren lassen), damit die cp210x usb-uart Wandler funktionieren.

    Code:
    Bus 001 Device 009: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x Composite Device
    Bus 001 Device 008: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x Composite Device
    Leider bekomme ich immer noch nur "Schrott" auf dem Device.
    Code:
    root@wiregate248:/home/user# socat - /dev/ttyUSBehzEMHHaupt,raw,echo=0,b9600,parenb=0,cs8,cstopb=1
    ��oMbbrcv
    MPNbbrcw;Wc"xv
               EMH�p;Wb
    ��rbe���ww��ǂ�EMHw    �
                                         EMH�p;Ww�d�bR�V��w�bR�V��w�bR�Vw�bR�U���
    oder
    Code:
    root@wiregate248:/home/user# socat - /dev/ttyUSBehzEMHHaupt,raw,echo=0,b9600,parenb=0,cs8,cstopb=1
    ��oMbbrcv
    MPNbbrcw;Wc"xv
               EMH�p;Wb
    ��rbe���ww��ǂ�EMHw    �
                                         EMH�p;Ww�d�bR�V��w�bR�V��w�bR�Vw�bR�U���
    Hat jemand eine Idee, was ich probieren kann?

    Danke und Gruß Moritz

    Einen Kommentar schreiben:


  • coolrunnings
    antwortet
    Zitat von mosjka1 Beitrag anzeigen
    Super, klasse! Vielen Dank!
    Kannst du bitte noch sagen wie oft du den Script über crontab ausführen lässt?
    Alle 5 Minuten.

    Zitat von mosjka1 Beitrag anzeigen
    Code:
    OBIS ID:     1.8.0
    OBIS search: 77070100010800FF
    found: 6400018001621E52FF56000158AFEF01
    check sml status:          [384]
    check sml value time:      [empty]
    check sml unit:            [30]
    check sml scaler:          [-1]
    check sml value:           [22589423]
    check sml value signature: [empty]
    Unit config: [kWh][cdg]
    Final value: [2258.9423 kWh]
    Das sieht gut aus. Wie gesagt, du kannst die COUNTER RRDs noch deaktivieren. Einfach
    Code:
    @countermodes =();
    Zitat von mosjka1 Beitrag anzeigen
    Code:
    OBIS ID:     16.7.0
    OBIS search: 77070100100700FF
    found: 0101621B52FF55000000C401
    check sml status:          [empty]
    check sml value time:      [empty]
    check sml unit:            [27]
    check sml scaler:          [-1]
    check sml value:           [196]
    check sml value signature: [empty]
    Unit config: [W][g]
    Final value: [19.6 W]
    Sieht auch soweit schlüssig aus. Aber 19,6W momentaner Verbrauch ist schon sportlich. Hast du noch nichts dran hängen?

    Zitat von mosjka1 Beitrag anzeigen
    Code:
    OBIS ID:     36.7.0
    OBIS ID:     76.7.0
    Die würde ich noch aus der Config entfernen.

    Einen Kommentar schreiben:


  • mosjka1
    antwortet
    Super, klasse! Vielen Dank!
    Kannst du bitte noch sagen wie oft du den Script über crontab ausführen lässt?

    Anbei nun der output:
    Code:
    wiregate:/etc/wiregate/plugin/generic/backup# perl zaehler3
    Step 1 - Collect data
    Step 2 - Reg Exp 1 build dataset
    1B1B1B1B01010101760700090154886D6200620072630101760101070009007082CF0B0901454D480000424ECD0101630B8900760700090154886E620062007263070177010B0901454D480000424ECD070100620AFFFF7262016500700BE27777078181C78203FF0101010104454D480177070100000009FF010101010B0901454D480000424ECD0177070100010800FF6400018001621E52FF56000158AFEF0177070100010801FF0101621E52FF56000158AFEF0177070100010802FF0101621E52FF5600000000000177070100100700FF0101621B52FF55000000C40177078181C78205FF017262016500700BE201018302000AA1993A626C62D3345F4C95977A5262309183F335956147F25996456B2152F3FE8490C451ACECC61C1B26FAEAB8FF01010163A24C00760700090154886F62006200726302017101631EC1000000001B1B1B1B1A0377C21B1B1B1B0101010176070009015488736200620072630101760101070009007082D10B0901454D480000424ECD010163FB68007607000901548874620062007263070177010B0901454D480000424ECD070100620AFFFF7262016500700BE37777078181C78203FF0101010104454D480177070100000009FF010101010B0901454D480000424ECD0177070100010800FF6400018201621E52FF56000158AFF00177070100010801FF0101621E52FF56000158AF1B1B1B1B0101010176070009015488D36200620072630101760101070009007082F10B0901454D480000424ECD01016370330076070009015488D4620062007263070177010B0901454D480000424ECD070100620AFFFF7262016500700C297777078181C78203FF0101010104454D480177070100000009FF010101010B0901454D480000424ECD0177070100010800FF6400018001621E52FF56000158AFF30177070100010801FF0101621E52FF56000158AFF30177070100010802FF0101621E52FF5600000000000177070100100700FF0101621B52FF55000000C90177078181C78205FF017262016500700C2901018302000AA1993A626C62D3345F4C95977A5262309183F335956147F25996456B2152F3FE8490C451ACECC61C1B26FAEAB8FF0101016395930076070009015488D5620062007263020171016342D7000000001B1B1B1B1A0322521B1B1B1B0101010176070009015488D96200620072630101760101070009007082F30B0901454D480000424ECD01016343830076070009015488DA620062007263070177010B0901454D480000424ECD070100620AFFFF7262016500700C2B7777078181C78203FF0101010104454D480177070100000009FF010101010B0901454D480000424ECD0177070100010800FF6400018201621E52FF56000158AFF40177070100010801FF0101621E52FF56000158AF
    Step 3 - Analyze data
    
    OBIS ID:     1.8.0
    OBIS search: 77070100010800FF
    found: 6400018001621E52FF56000158AFEF01
    check sml status:          [384]
    check sml value time:      [empty]
    check sml unit:            [30]
    check sml scaler:          [-1]
    check sml value:           [22589423]
    check sml value signature: [empty]
    Unit config: [kWh][cdg]
    Final value: [2258.9423 kWh]
    COUNTER
    obisname  zaehler_verbrauch
    value     2258.9423
    rrdname   zaehler_verbrauch_5_c.rrd
    [2258.9423]*[5]*[60] = 677682 countervalue
    rrdname   zaehler_verbrauch_15_c.rrd
    [2258.9423]*[15]*[60] = 2033048 countervalue
    rrdname   zaehler_verbrauch_60_c.rrd
    [2258.9423]*[60]*[60] = 8132192 countervalue
    rrdname   zaehler_verbrauch_1440_c.rrd
    [2258.9423]*[1440]*[60] = 195172614 countervalue
    DERIVE
    obisname  zaehler_verbrauch
    value     2258.9423
    rrdname   zaehler_verbrauch_5_d.rrd
    [2258.9423]*[5]*[60] = 677682 derivevalue
    rrdname   zaehler_verbrauch_15_d.rrd
    [2258.9423]*[15]*[60] = 2033048 derivevalue
    rrdname   zaehler_verbrauch_60_d.rrd
    [2258.9423]*[60]*[60] = 8132192 derivevalue
    rrdname   zaehler_verbrauch_1440_d.rrd
    [2258.9423]*[1440]*[60] = 195172614 derivevalue
    GAUGE
    obisname  zaehler_verbrauch
    value     2258.9423
    rrdname   zaehler_verbrauch_g.rrd
    GA:9/0/0 value:2258.9423 DPT:14
    
    OBIS ID:     16.7.0
    OBIS search: 77070100100700FF
    found: 0101621B52FF55000000C401
    check sml status:          [empty]
    check sml value time:      [empty]
    check sml unit:            [27]
    check sml scaler:          [-1]
    check sml value:           [196]
    check sml value signature: [empty]
    Unit config: [W][g]
    Final value: [19.6 W]
    GAUGE
    obisname  zaehler_leistung
    value     19.6
    rrdname   zaehler_leistung_g.rrd
    GA:9/0/1 value:19.6 DPT:9
    
    OBIS ID:     36.7.0
    OBIS search: 77070100240700FF
    Use of uninitialized value $1 in concatenation (.) or string at zaehler3 line 91.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    
    OBIS ID:     56.7.0
    OBIS search: 77070100380700FF
    Use of uninitialized value $1 in concatenation (.) or string at zaehler3 line 91.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    
    OBIS ID:     76.7.0
    OBIS search: 770701004C0700FF
    Use of uninitialized value $1 in concatenation (.) or string at zaehler3 line 91.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short

    Einen Kommentar schreiben:


  • coolrunnings
    antwortet
    Also ich hab auch nen Zähler von der RWE, aber den ISKRA und nicht den EMH. Damit klappt es einwandfrei.

    Ich hab den Code mal angepasst, so dass die 4 für 24 bit steht und 6 für 40 bit. Konnte darüber allerdings nichts in der Spezi finden. Dann sähen die OBIS Daten so aus:

    Code:
    	  
    77 
      07 01 00 01 08 00 FF   # ID 1-1.8.0
        64 00 01 82              # Status 0x182 --> 386
        01                          # keine Zeit 
        62 1E                      # Unit 0x1E --> 30 --> Wh
        52  FF                     # Scaler -1 --> value+10^-1
        56 00 01 58 3F 53     # Value: 0x1583F53 --> 22560595 Wh --> 2256,0595 kWh
        01                          # keine value Signatur
    Du hast du OBIS IDs 1.8.0, 1.8.1, 1.8.2 und 16.7.0
    Hier der Code:

    Code:
    #!/usr/bin/perl
    #
    # Autor: coolrunnings / www.knx-user-forum.de
    # Based on the PlugIn sml-meter by JuMi2006 / www.knx-user-forum.de
    # knx_write sub: makki / www.knx-user-forum.de
    # Version: 0.2
    # Datum: 03.11.2013
    # Licenced under the GPLv3
    
    use warnings;
    use strict;
    use Device::SerialPort;
    use feature "switch";
    use EIBConnection;
    use RRDs;
    use Scalar::Util qw(looks_like_number);
    
    #####################################################################
    # define everything here
    my $eib_url = "local:/tmp/eib";     #for local eibd "local:/tmp/eib" for eibd in LAN: "ip:192.168.2.220:6720"
    my $device = "/dev/ttyUSB0";
    my $rrdpath = "/var/www/rrd";
    
    my @obis;
    push @obis,{obis=>"1.8.0",  ga =>"9/0/0", dpt =>  14, rrd_name => "zaehler_verbrauch"}; 
    push @obis,{obis=>"16.7.0", ga =>"9/0/1", dpt =>  9, rrd_name => "zaehler_leistung" };
    push @obis,{obis=>"36.7.0", ga =>"9/0/2", dpt =>  9, rrd_name => "zaehler_leistung_L1"};
    push @obis,{obis=>"56.7.0", ga =>"9/0/3", dpt =>  9, rrd_name => "zaehler_leistung_L2"};
    push @obis,{obis=>"76.7.0", ga =>"9/0/4", dpt =>  9, rrd_name => "zaehler_leistung_L3"};
    my @countermodes = (5,15,60,1440);    #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
    my @derivemodes = (5,15,60,1440);    #Aufloesungen fuer DERIVE RRDs in Minuten (1440 = Tagesverbrauch)
    
    my $debug   = "1";
    my $logging = "1";
    my $port = Device::SerialPort->new($device) || die $!;
    $port->databits(8);
    $port->baudrate(9600);
    $port->parity("none");
    $port->stopbits(1);
    $port->handshake("none");
    $port->write_settings;
    $port->dtr_active(1);
    $port->purge_all();
    $port->read_char_time(0);     # don't wait for each character
    $port->read_const_time(2000); # 1 second per unfulfilled "read" call
    
    #####################################################################
    # don't touch anything starting here
    
    my $filename = "/tmp/sml_meter.log";
    if ( $logging == "1" ) {open (LOG, ">>$filename") or $logging = "0";}
    
    if ( $logging == "1" ) {print LOG "===============================================\n";}
    if ( $logging == "1" ) {print LOG (localtime)." Start new run\n";}
    
    
    my ($x,$rawdata) = 0 ;
    my $count = 0;
    my $saw = 0;
    my $start = 0;
    
    if ($debug == 1) {print "Step 1 - Collect data \n";}
    if ($logging == 1) {print LOG "Step 1 - Collect data \n";}
    
    while ($start < 2) {	# wait for second 1B1B1B1B01010101
       
    	($count,$saw)=$port->read(512);  # will read 512 chars
    	if ($count == 512) {       		# 512 chars read?
    		$x = uc(unpack('H*',$saw)); # nach hex wandeln
    		$rawdata .= $x;
    		if ($rawdata =~ /1B1B1B1B01010101/)  {$start ++};
    	} # if
    }  # while
    
    if ($debug==1) {print "Step 2 - Reg Exp 1 build dataset \n";}
    if ($logging==1) {print LOG "Step 2 - Reg Exp 1 build dataset \n";}
    
    $rawdata =~ m/1B1B1B1B01010101(.*?)B1B1B1/;
    print $rawdata."\n";
    
    if ($debug==1) {print "Step 3 - Analyze data \n";}
    if ($logging==1) {print LOG "Step 3 - Analyze data \n";}
    
    # find OBIS values in raw data
    foreach my $obiscnt (@obis) {
    	if ( $debug == 1 ) {print "\n";}
    	if ( $logging == 1 ) {print LOG "-----------------------------------------------\n";}
    	my $obissearch = &obis2search($obiscnt->{obis});
    	
    	$rawdata =~ m/$obissearch(.*?)017707/;
    	my $obisdata = $1."01";
    	
    	if ( $debug == 1 ) {print "found: ".$obisdata."\n";}
    	if ( $logging == 1 ) {print LOG "found: ".$obisdata."\n";}
    	
    	my $smlStatus  = "";
    	my $smlValTime = "";
    	my $smlUnit    = "";
    	my $smlScaler  = "";
    	my $smlValue   = "";
    	my $smlValueS  = "";
    	
    	## check status
    	if ( $debug == 1 ) {print "check sml status:          ";}
    	if ( $logging == 1 ) {print LOG "check sml status:          ";}
    	$smlStatus = &parseOBIS(\$obisdata);
    	
    	## check value time
    	if ( $debug == 1 ) {print "check sml value time:      ";}
    	if ( $logging == 1 ) {print LOG "check sml value time:      ";}
    	$smlValTime = &parseOBIS(\$obisdata);
    	
    	## check unit
    	if ( $debug == 1 ) {print "check sml unit:            ";}
    	if ( $logging == 1 ) {print LOG "check sml unit:            ";}
    	$smlUnit = &parseOBIS(\$obisdata);
    	
    	## check scaler
    	if ( $debug == 1 ) {print "check sml scaler:          ";}
    	if ( $logging == 1 ) {print LOG "check sml scaler:          ";}
    	$smlScaler = &parseOBIS(\$obisdata);
    	
    	## check value
    	if ( $debug == 1 ) {print "check sml value:           ";}
    	if ( $logging == 1 ) {print LOG "check sml value:           ";}
    	$smlValue = &parseOBIS(\$obisdata);
    	
    	## check value signature
    	if ( $debug == 1 ) {print "check sml value signature: ";}
    	if ( $logging == 1 ) {print LOG "check sml value signature: ";}
    	$smlValueS = &parseOBIS(\$obisdata);
    
    	#print "done: ".$obisdata."\n";
    	#print  $smlStatus;
    	
    	# Calculate value
    	if ( $smlValue ne "" ) {
    		my $calcvalue  = ($smlValue * (10**$smlScaler));
    		
    		# Modify value depening on unit
    		my $smlUnitCfg_ref = &getSMLUnitStr($smlUnit);
    		my @smlUnitCfg = @{$smlUnitCfg_ref};
    		
    		if ( (@smlUnitCfg) == 2 ) {
    			my $tUnitStr  = $smlUnitCfg[0];
    			my $tUnitRRD  = $smlUnitCfg[1];
    			
    			# Wh to kWh
    			if ( $smlUnit == 30  ) {
    				$calcvalue = $calcvalue * 0.001;
    				$tUnitStr  = "kWh";
    			}
    			
    			if ( $debug == 1 ) {print "Unit config: [".$tUnitStr."][".$tUnitRRD."]\n";}
    			if ( $logging == 1 ) {print LOG "Unit config: [".$tUnitStr."][".$tUnitRRD."]\n";}
    			
    			if ( $debug == 1 ) {print "Final value: [".$calcvalue." ".$tUnitStr."]\n";}
    			if ( $logging == 1 ) {print LOG "Final value: [".$calcvalue." ".$tUnitStr."]\n";}
    		
    			# write rrd
    			if ($tUnitRRD =~ m/c/) {
    				&rrd_counter ($obiscnt->{rrd_name},$calcvalue)
    			}
    			
    			if ($tUnitRRD =~ m/d/) {
    				&rrd_derive ($obiscnt->{rrd_name},$calcvalue)
    			}
    			
    			if ($tUnitRRD =~ m/g/) {
    				&rrd_gauge ($obiscnt->{rrd_name},$calcvalue)
    			}
    
    			# send value to bus
    			&knx_write ($obiscnt->{ga},$calcvalue,$obiscnt->{dpt});
    			if ($debug == 1) {print "GA:".$obiscnt->{ga}." value:".$calcvalue." DPT:".$obiscnt->{dpt}."\n";}
    			if ($logging == 1) {print LOG "GA:".$obiscnt->{ga}." value:".$calcvalue." DPT:".$obiscnt->{dpt}."\n";}
    				
    				
    		}
    		else {
    			if ( $debug == 1 ) {print "No unit found. No data will be written.\n";}
    			if ( $logging == 1 ) {print LOG "No unit found. No data will be written.\n";}
    		}
    	}	
    }
    
    $port->close() || warn "Serial port did not close proper!\n";
    undef $port;
    
    if ( $logging == "1" ) {close LOG;}
    
    ## subs ##
    
    #####################################################################
    # convert OBIS to search parameter
    sub obis2search {
    
    	my ($obisid) = @_;
    	my $res = "77070100";
    	
    	if ($debug==1) { print "OBIS ID:     ".$obisid."\n";}
    	if ($logging==1) { print LOG "OBIS ID:     ".$obisid."\n";}
    		
    	foreach my $c ( split(/\./,$obisid) ) {
    		$res .= sprintf("%02X",$c);
    	}
    	
    	$res .= "FF";
    	
    	if ($debug==1) { print "OBIS search: ".$res."\n";}
    	if ($logging==1) { print LOG "OBIS search: ".$res."\n";}
    	
    	return $res;
    }
    
    #####################################################################
    # parse OBIS data
    sub parseOBIS {
    	#my ($obisdata) = @_;
    	my $r_obisdata = shift;
    	my $res = "";
    	
    	if ( length($$r_obisdata) < 2 ) {
    		print "error --> data too short\n";
    		return $res;
    	}
    	
    	my $smlDataTypeID = substr($$r_obisdata,0,2); 
    	
    	if ( $smlDataTypeID == "01" ) {
    		## no data
    		if ( $debug == 1 ) {print "[empty]\n";}
    		if ( $logging == 1 ) {print LOG "[empty]\n";}
    		$$r_obisdata =~ s/^..//;	# remove first 2 characters
    		return $res;
    	}
    	else {
    		#if ( $debug == 1 ) {print "found something ";}
    		#if ( $logging == 1 ) {print LOG "found something ";}
    		
    		my $smlDataType    = substr($smlDataTypeID,0,1);
    		my $smlIntBitCode = substr($smlDataTypeID,1,1);
    		
    		# only signed and unsigned int possible
    		if ( $smlDataType != "5" && $smlDataType != "6") {
    			if ( $debug == 1 ) {print "Invalid datatype [".$smlDataType."]\n"; };
    			if ( $logging == 1 ) {print LOG "Invalid datatype [".$smlDataType."]\n"; };
    			return $res;
    		}
    		
    		$$r_obisdata =~ s/^..//;	# remove first 2 characters
    		
    		
    		my $smlIntBitCnt = 0;
    		
    		#switch ( $smlIntBitCode ) {
    		#	case 2	{ $smlIntBitCnt =  8 }
    		#	case 3	{ $smlIntBitCnt = 16 }
    		#	case 5	{ $smlIntBitCnt = 32 }
    		#	case 9	{ $smlIntBitCnt = 64 }
    		#	else  	{ if ( $debug == 1 ) {print "Invalid integer bit count [".$smlIntBitCode."]\n"; };
    		#			  return $res; 
    		#			}
    		#}
    		
    		if ( $smlIntBitCode == 2 ) {
    			$smlIntBitCnt =  8
    		}
    		elsif ( $smlIntBitCode == 3 ) {
    			$smlIntBitCnt =  16
    		}
    		elsif ( $smlIntBitCode == 4 ) { # not conform with the SML specification!
    			$smlIntBitCnt =  24
    		}
    		elsif ( $smlIntBitCode == 5 ) {
    			$smlIntBitCnt =  32
    		}
            elsif ( $smlIntBitCode == 6 ) { # not conform with the SML specification!
    			$smlIntBitCnt =  40
    		}
    		elsif ( $smlIntBitCode == 9 ) {
    			$smlIntBitCnt =  64
    		}
    		else {
    			if ( $debug == 1 ) {print "Invalid integer bit count [".$smlIntBitCode."]\n"; };
    			if ( $logging == 1 ) {print LOG "Invalid integer bit count [".$smlIntBitCode."]\n"; };
    			return $res;
    		}
    		
    		my $smlIntCharCnt = ($smlIntBitCnt/4);
    		
    		# check that the rest of the string is long enought for the bit count
    		if ( (length($$r_obisdata)) < $smlIntCharCnt ) {
    			if ( $debug == 1 ) {print "String not long enough for for detected bit count [".$smlIntCharCnt."]\n"; };
    			if ( $logging == 1 ) {print LOG "String not long enough for for detected bit count [".$smlIntCharCnt."]\n"; };
    			return $res;
    		}
    		
    		# get the hex values
    		my $hexval = substr($$r_obisdata,0,$smlIntCharCnt);
    		$$r_obisdata = substr($$r_obisdata,$smlIntCharCnt);
    		
    		# if signed, get 2' complement
    		if ( $smlDataType == 5 ) {
    			my $hexbin = sprintf("%0${smlIntBitCnt}b",hex($hexval));
    		
    			if ( substr($hexbin,0,1) == 1 ) {
    				#if ( $debug == 1 ) { print "2's complement \n"; }
    				#if ( $logging == 1 ) { print LOG "2's complement \n"; }
    				my $hexinv = sprintf("%08x",~hex($hexval));
    				$res = (substr($hexinv,6,2)+1)*(-1);
    			
    			}
    			else {
    				$res = hex($hexval);
    			}
    		}
    		else {
    			$res = hex($hexval);
    		}
    		
    		if ( $debug == 1 ) { print "[".$res."]\n";}
    		if ( $logging == 1 ) { print LOG "[".$res."]\n";}
    		
    		return $res;
    	}
    	
    	return $res;
    }
    
    #####################################################################
    # get SML unit string depending on value
    # DLMS Units as specified in ISO EN 62056-62 and used by SML
    # original values from unit.h in vzlogger project
    # The volkszaehler.org project
    sub getSMLUnitStr {
    
    	my ($smlUnitCode) = @_;
    	
    	my %unitmap = (	
    	# code	  # unit		#rrd		# quantity						#name					#SI definition
    	
    	1 => 	[ "a",			"g" ],      # time                			year            		52*7*24*60*60 s
    	2 => 	[ "mo",			"g" ],      # time                			month            		31*24*60*60 s
    	3 => 	[ "wk",			"g" ],      # time                			week            		7*24*60*60 s
    	4 => 	[ "d",			"g" ],      # time                			day            			24*60*60 s
    	5 => 	[ "h",			"g" ],      # time                			hour            		60*60 s
    	6 => 	[ "min.",		"g" ],      # time                			min            			60 s
    	7 => 	[ "s",			"g" ],      # time (t)            			second            		s
    	8 => 	[ "°",			"g" ],      # (phase) angle        			degree            		rad*180/π
    	9 => 	[ "°C",			"g" ],      # temperature (T)       		degree celsius      	K-273.15
    	10 => 	[ "currency",	"g" ],    	# (local) currency
    	11 => 	[ "m",			"g" ],      # length (l)            		metre            		m
    	12 => 	[ "m/s",		"g" ],      # speed (v)            			metre per second    	m/s
    	13 => 	[ "m³",			"g" ],      # volume (V)            		cubic metre        		m³
    	14 => 	[ "m³",			"g" ],      # corrected volume      		cubic metre        		m³
    	15 => 	[ "m³/h",		"g" ],      # volume flux           		cubic metre per hour    m³/(60*60s)
    	16 => 	[ "m³/h",		"g" ],      # corrected volume flux 		cubic metre per hour    m³/(60*60s)
    	17 => 	[ "m³/d",		"g" ],      # volume flux                        					m³/(24*60*60s)
    	18 => 	[ "m³/d",		"g" ],      # corrected volume flux                					m³/(24*60*60s)
    	19 => 	[ "l",			"g" ],      # volume            			litre            		10-3 m³
    	20 => 	[ "kg",			"g" ],      # mass (m)            			kilogram
    	21 => 	[ "N",			"g" ],      # force (F)            			newton
    	22 => 	[ "Nm",			"g" ],      # energy            			newtonmeter        		J = Nm = Ws
    	23 => 	[ "Pa",			"g" ],      # pressure (p)          		pascal            		N/m²
    	24 => 	[ "bar",		"g" ],      # pressure (p)          		bar            			10⁵ N/m²
    	25 => 	[ "J",			"g" ],      # energy            			joule            		J = Nm = Ws
    	26 => 	[ "J/h",		"g" ],      # thermal power        			joule per hour        	J/(60*60s)
    	27 => 	[ "W",			"g" ],      # active power (P)      		watt            		W = J/s
    	28 => 	[ "VA",			"g" ],      # apparent power (S)    		volt-ampere
    	29 => 	[ "var",		"g" ],      # reactive power (Q)    		var
    	30 => 	[ "Wh",			"cdg" ],    # active energy        			watt-hour        		W*(60*60s)
    	31 => 	[ "VAh",		"g" ],      # apparent energy       		volt-ampere-hour    	VA*(60*60s)
    	32 => 	[ "varh",		"g" ],      # reactive energy       		var-hour        		var*(60*60s)
    	33 => 	[ "A",			"g" ],      # current (I)           		ampere            		A
    	34 => 	[ "C",			"g" ],      # electrical charge (Q) 		coulomb            		C = As
    	35 => 	[ "V",			"g" ],      # voltage (U)           		volt            		V
    	36 => 	[ "V/m",		"g" ],      # electr. field strength (E)    volt per metre
    	37 => 	[ "F",			"g" ],      # capacitance (C)       		farad            		C/V = As/V
    	38 => 	[ "Ω",			"g" ],      # resistance (R)        		ohm            			Ω = V/A
    	39 => 	[ "Ωm²/m",		"g" ],      # resistivity (ρ)       		Ωm
    	40 => 	[ "Wb",			"g" ],      # magnetic flux (Φ)     		weber            		Wb = Vs
    	41 => 	[ "T",			"g" ],      # magnetic flux density (B)    	tesla            		Wb/m2
    	42 => 	[ "A/m",		"g" ],      # magnetic field strength (H)   ampere per metre    	A/m
    	43 => 	[ "H",			"g" ],      # inductance (L)        		henry            		H = Wb/A
    	44 => 	[ "Hz",			"g" ],      # frequency (f => ω)        	hertz            		1/s
    	45 => 	[ "1/(Wh)",		"g" ],      # R_W                           (Active energy meter constant or pulse value)
    	46 => 	[ "1/(varh)",	"g" ],     	# R_B                           (reactive energy meter constant or pulse value)
    	47 => 	[ "1/(VAh)",	"g" ],    	# R_S                           (apparent energy meter constant or pulse value)
    	48 => 	[ "V²h",		"g" ],      # volt-squared hour        	´	volt-squaredhours    	V²(60*60s)
    	49 => 	[ "A²h",		"g" ],      # ampere-squared hour        	ampere-squaredhours    	A²(60*60s)
    	50 => 	[ "kg/s",		"g" ],      # mass flux            			kilogram per second    	kg/s
    	51 => 	[ "S => mho",	"g" ],     	# conductance siemens                    				1/Ω
    	52 => 	[ "K",			"g" ],     	# temperature (T)        		kelvin
    	53 => 	[ "1/(V²h)",	"g" ],    	# R_U²h                        (Volt-squared hour meter constant or pulse value)
    	54 => 	[ "1/(A²h)",	"g" ],    	# R_I²h                        (Ampere-squared hour meter constant or pulse value)
    	55 => 	[ "1/m³",		"g" ],      # R_V => meter constant or pulse value (volume)
    	56 => 	[ "%",			"g" ],      # percentage            		%
    	57 => 	[ "Ah",			"g" ],      # ampere-hours            		ampere-hour
    	60 => 	[ "Wh/m³",		"g" ],      # energy per volume                    					3,6*103 J/m³
    	61 => 	[ "J/m³",		"g" ],      # calorific value, wobbe
    	62 => 	[ "Mol %",		"g" ],      # molar fraction of        		mole percent    (Basic gas composition unit)
    										# gas composition  
    	63 => 	[ "g/m³",		"g" ],      # mass density, quantity of material            (Gas analysis => accompanying elements)
    	64 => 	[ "Pa s",		"g" ],      # dynamic viscosity pascal second       		(Characteristic of gas stream)
    	253 => 	[ "(reserved)",	"g"],		# reserved
    	254 => 	[ "(other)",	"g" ],    	# other unit
    	255 => 	[ "(unitless)",	"g"]   	# no unit, unitless, count
    	);
    	
    	#print "-------- unit ".$unitmap{$smlUnitCode}[0]."\n";
    	
    	#print "-------- unit ".$unitmap{$smlUnitCode}."\n";
    	
    	my $unitarray_ref = $unitmap{$smlUnitCode};
    	
    	return $unitarray_ref;
    	
    }
    
    #####################################################################
    
    sub knx_write {
        my ($dst,$value,$dpt,$response,$dbgmsg) = @_;
        my $bytes;
        my $apci = ($response) ? 0x40 : 0x80; # 0x40=response, 0x80=write
        #     DPT 1 (1 bit) = EIS 1/7 (move=DPT 1.8, step=DPT 1.7)
        #     DPT 2 (1 bit controlled) = EIS 8
        #     DPT 3 (3 bit controlled) = EIS 2
        #     DPT 4 (Character) = EIS 13
        #     DPT 5 (8 bit unsigned value) = EIS 6 (DPT 5.1) oder EIS 14.001 (DPT 5.10)
        #     DPT 6 (8 bit signed value) = EIS 14.000
        #     DPT 7 (2 byte unsigned value) = EIS 10.000
        #     DPT 8 (2 byte signed value) = EIS 10.001
        #     DPT 9 (2 byte float value) = EIS 5
        #     DPT 10 (Time) = EIS 3
        #     DPT 11 (Date) = EIS 4
        #     DPT 12 (4 byte unsigned value) = EIS 11.000
        #     DPT 13 (4 byte signed value) = EIS 11.001
        #     DPT 14 (4 byte float value) = EIS 9
        #     DPT 15 (Entrance access) = EIS 12
        #     DPT 16 (Character string) = EIS 15
        # $dpt = $eibgaconf{$dst}{'DPTSubId'} unless $dpt; # read dpt from eibgaconf if existing
        given ($dpt) {
            when (/^12/)             { $bytes = pack ("CCL>", 0, $apci, $value); }  #EIS11.000/DPT12 (4 byte unsigned)
            when (/^13/)             { $bytes = pack ("CCl>", 0, $apci, $value); }
            when (/^14/)             { $bytes = pack ("CCf>", 0, $apci, $value); }
            when (/^16/)             { $bytes = pack ("CCa14", 0, $apci, $value); }
            when (/^17/)             { $bytes = pack ("CCC", 0, $apci, $value & 0x3F); }
            when (/^20/)             { $bytes = pack ("CCC", 0, $apci, $value); }
            when (/^\d\d/)           { return; } # other DPT XX 15 are unhandled
            when (/^[1,2,3]/)        { $bytes = pack ("CC", 0, $apci | ($value & 0x3f)); } #send 6bit small
            when (/^4/)              { $bytes = pack ("CCc", 0, $apci, ord($value)); }
            when ([5,5.001])         { $bytes = pack ("CCC", 0, $apci, encode_dpt5($value)); } #EIS 6/DPT5.001 1byte
            when ([5.004,5.005,5.010]) { $bytes = pack ("CCC", 0, $apci, $value); }
            when (/^5/)              { $bytes = pack ("CCC", 0, $apci, $value); }
            when (/^6/)              { $bytes = pack ("CCc", 0, $apci, $value); }
            when (/^7/)              { $bytes = pack ("CCS>", 0, $apci, $value); }
            when (/^8/)              { $bytes = pack ("CCs>", 0, $apci, $value); }
            when (/^9/)              { $bytes = pack ("CCCC", 0, $apci, encode_dpt9($value)); } #EIS5/DPT9 2byte float
            default                  { LOGGER('WARN',"None or unsupported DPT: $dpt sent to $dst value $value"); return; }
        }
        my $leibcon = EIBConnection->EIBSocketURL($eib_url) or return("Error opening con: $!");
        if ($leibcon->EIBOpenT_Group(str2addr($dst),1) == -1) { return("Error opening group: $!"); }
        my $res=$leibcon->EIBSendAPDU($bytes);
        $leibcon->EIBClose();
        return $res;
        
        # str2addr: Convert an EIB address string in the form "1/2/3" or "1.2.3" to an integer
        sub str2addr {
            my $str = $_[0];
            if ($str =~ /(\d+)\/(\d+)\/(\d+)/) { # logical address
                return ($1 << 11) | ($2 << 8) | $3;
            } elsif ($str =~ /(\d+)\.(\d+)\.(\d+)/) { # physical address
                return ($1 << 12) | ($2 << 8) | $3;
            } else {
                #bad
                return;
            }
        }
        
    }
    
    #####################################################################
    
    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;
    }
    
    #####################################################################
    
    sub rrd_counter
    {
        if ($debug==1){print ("COUNTER","\n")};
    	if ($logging==1){print LOG ("-- COUNTER ---","\n")};
    	
    	my $obisname = $_[0];
    	if ($debug==1){print "obisname  ".$obisname."\n";}
    	if ($logging==1){print LOG "obisname  ".$obisname."\n";}
    	my $value = $_[1];
        if ($debug==1){print "value     ".$value."\n";}
    	if ($logging==1){print LOG "value     ".$value."\n";}
        
        foreach (@countermodes)
        {
            my $rrdname = $obisname."_".$_."_c\.rrd";
            if ($debug==1){print "rrdname   ".$rrdname."\n"};
    		if ($logging==1){print LOG "----------\n"};
    		if ($logging==1){print LOG "rrdname   ".$rrdname."\n"};
            my $rrdfile = $rrdpath."\/".$rrdname;
            unless (-e $rrdfile)
            {
                RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:U",
    			"RRA:AVERAGE:0.5:1:366",	
    			"RRA:AVERAGE:0.5:7:1308",
    			"-s ".($_*60));				# step 
            }
            my $countervalue = int($value*$_*60);
    		if ($debug==1){print "[".$value."]*[".$_."]*[60] = ".$countervalue." countervalue \n";}
    		if ($logging==1){print LOG "[".$value."]*[".$_."]*[60] = ".$countervalue." countervalue \n";}
            RRDs::update("$rrdfile", "N:$countervalue");
        }
    }
    
    sub rrd_derive
    {
        if ($debug==1){print ("DERIVE","\n")};
    	if ($logging==1){print LOG ("-- DERIVE ---","\n")};
    	
    	my $obisname = $_[0];
    	if ($debug==1){print "obisname  ".$obisname."\n";}
    	if ($logging==1){print LOG "obisname  ".$obisname."\n";}
    	my $value = $_[1];
        if ($debug==1){print "value     ".$value."\n";}
    	if ($logging==1){print LOG "value     ".$value."\n";}
        
        foreach (@derivemodes)
        {
            my $rrdname = $obisname."_".$_."_d\.rrd";
            if ($debug==1){print "rrdname   ".$rrdname."\n"};
    		if ($logging==1){print LOG "----------\n"};
    		if ($logging==1){print LOG "rrdname   ".$rrdname."\n"};
            my $rrdfile = $rrdpath."\/".$rrdname;
            unless (-e $rrdfile)
            {
                RRDs::create ($rrdfile,"DS:value:DERIVE:".(($_*60)+600).":0:U",
    			"RRA:AVERAGE:0.5:1:366",	
    			"RRA:AVERAGE:0.5:7:1308",
    			"-s ".($_*60));				# step 
            }
            my $derivevalue = int($value*$_*60);
    		if ($debug==1){print "[".$value."]*[".$_."]*[60] = ".$derivevalue." derivevalue \n";}
    		if ($logging==1){print LOG "[".$value."]*[".$_."]*[60] = ".$derivevalue." derivevalue \n";}
            RRDs::update("$rrdfile", "N:$derivevalue");
        }
    }
    
    #####################################################################
    
    sub rrd_gauge
    {
        if ($debug==1){print ("GAUGE","\n")};
    	if ($logging==1){print LOG ("-- GAUGE --","\n")};
        my $obisname = $_[0];
        if ($debug==1){print "obisname  ".$obisname."\n";}
    	if ($logging==1){print LOG "obisname  ".$obisname."\n";}
    	my $value = $_[1];
        if ($debug==1){print "value     ".$value."\n";}
    	if ($logging==1){print LOG "value     ".$value."\n";}
        my $rrdname = $obisname."_g\.rrd";
        if ($debug==1){print "rrdname   ".$rrdname."\n"};
    	if ($logging==1){print LOG "rrdname   ".$rrdname."\n"};
        my $rrdfile = $rrdpath."\/".$rrdname;
        unless (-e $rrdfile)
        {
            RRDs::create ($rrdfile,"DS:value:GAUGE:900:0:U",
    		"RRA:AVERAGE:0.5:1:2016",		# 5 minutes for 7 days
    		"RRA:AVERAGE:0.5:6:1488",		# 30 minutes for 31 days
    		"RRA:AVERAGE:0.5:12:4392",		# 1 hour for 5 month
    		"RRA:AVERAGE:0.5:72:7320",		# 6 hours for 5 years
    		"RRA:AVERAGE:0.5:2016:1308");	# 1 day for 25 years	
        }
        RRDs::update("$rrdfile", "N:$value");
    }

    Einen Kommentar schreiben:


  • mosjka1
    antwortet
    Zitat von coolrunnings Beitrag anzeigen
    Was hast du denn für einen Zähler?
    Ich habe mir mal die Daten angeschaut. Da kommen ganz komische Sachen rüber, z.B.:

    Code:
          
    77 
      07 01 00 01 08 00 FF 
        64 00 01
        82 01
        62 1E 52 FF 56 00 01
        58 3F 53 01
    Das sollte eigentlich der aktuelle Zählerstand sein (1.8.0).
    Die 3. Zeile ist der Status. Die 6 am Anfang besagt, dass es sich um einen unsigned Wert handelt. Die bit Anzahl danach darf aber nur 2 (8 bit), 3 (16 bit), 5 (32 bit) oder 9 (64 bit) sein. So steht es zumindest in der Norm.

    Gruß
    Hi,

    von dem Zähler hab ich ein Foto angehangen.

    Danke für die Unterstützung
    Angehängte Dateien

    Einen Kommentar schreiben:


  • coolrunnings
    antwortet
    Was hast du denn für einen Zähler?
    Ich habe mir mal die Daten angeschaut. Da kommen ganz komische Sachen rüber, z.B.:

    Code:
    	  
    77 
      07 01 00 01 08 00 FF 
        64 00 01
        82 01
        62 1E 52 FF 56 00 01
        58 3F 53 01
    Das sollte eigentlich der aktuelle Zählerstand sein (1.8.0).
    Die 3. Zeile ist der Status. Die 6 am Anfang besagt, dass es sich um einen unsigned Wert handelt. Die bit Anzahl danach darf aber nur 2 (8 bit), 3 (16 bit), 5 (32 bit) oder 9 (64 bit) sein. So steht es zumindest in der Norm.

    Gruß

    Einen Kommentar schreiben:


  • mosjka1
    antwortet
    Anbei:

    Code:
    wiregate:/etc/wiregate/plugin/generic/backup# perl zahler2
    Step 1 - Collect data
    Step 2 - Reg Exp 1 build dataset
    51ACECC61C1B26FAEAB8FF0101016351AC00760700090153E827620062007263020171016322D4000000001B1B1B1B1A03DD611B1B1B1B01010101760700090153E8296200620072630101760101070009006F4D630B0901454D480000424ECD010163237C00760700090153E82A620062007263070177010B0901454D480000424ECD070100620AFFFF72620165006FC55D7777078181C78203FF0101010104454D480177070100000009FF010101010B0901454D480000424ECD0177070100010800FF6400018201621E52FF560001583F4A0177070100010801FF0101621E52FF560001583F4A0177070100010802FF0101621E52FF5600000000000177070100100700FF0101621B52FF55000055C50177078181C78205FF0172620165006FC55D01018302000AA1993A626C62D3345F4C95977A5262309183F335956147F25996456B2152F3FE8490C451ACECC61C1B26FAEAB8FF010101632BCD00760700090153E82D6200620072630201710163AAC3000000001B1B1B1B1A0319961B1B1B1B01010101760700090153E82F6200620072630101760101070009006F4D650B0901454D480000424ECD010163134900760700090153E830620062007263070177010B0901454D480000424ECD070100620AFFFF72620165006FC55E7777078181C78203FF0101010104454D480177070100000009FF010101010B0901454D480000424ECD0177070100010800FF6400018201621E52FF560001583F530177070100010801FF0101621E52FF560001583F530177070100010802FF0101621E52FF5600000000000177070100100700FF0101621B52FF55000056B50177078181C78205FF0172620165006FC55F01018302000AA1993A626C62D3345F4C95977A5262309183F335956147F25996456B2152F3FE8490C451ACECC61C1B26FAEAB8FF0101016319EF00760700090153E833620062007263020171016332FB000000001B1B1B1B1A0392FF1B1B1B1B01010101760700090153E8356200620072630101760101070009006F4D670B0901454D480000424ECD01016377B700760700090153E836620062007263070177010B0901454D480000424ECD070100620AFFFF72620165006FC5607777078181C78203FF0101010104454D480177070100000009FF010101010B0901454D480000424ECD0177070100010800FF6400018201621E52FF560001583F5C0177070100010801FF0101621E52FF560001583F5C0177070100010802FF0101621E52FF5600000000000177070100100700FF0101621B52FF55000057280177078181C78205FF0172620165006FC56001018302000AA1993A626C62D3345F4C95977A5262309183F335956147F25996456B2152F3FE8490C451ACECC61C1B26FAEAB8FF0101016390CB00760700090153E8396200
    Step 3 - Analyze data
    
    OBIS ID:     1.8.0
    OBIS search: 77070100010800FF
    found: 6400018201621E52FF560001583F4A01
    check sml status:          Invalid integer bit count [4]
    check sml value time:      Invalid datatype [0]
    check sml unit:            Invalid datatype [0]
    check sml scaler:          Invalid datatype [0]
    check sml value:           Invalid datatype [0]
    check sml value signature: Invalid datatype [0]
    
    OBIS ID:     16.7.0
    OBIS search: 77070100100700FF
    found: 0101621B52FF55000055C501
    check sml status:          [empty]
    check sml value time:      [empty]
    check sml unit:            [27]
    check sml scaler:          [-1]
    check sml value:           [21957]
    check sml value signature: [empty]
    Unit config: [W][g]
    Final value: [2195.7 W]
    GAUGE
    obisname  zaehler_leistung
    value     2195.7
    rrdname   zaehler_leistung_g.rrd
    GA:9/0/1 value:2195.7 DPT:9
    
    OBIS ID:     36.7.0
    OBIS search: 77070100240700FF
    Use of uninitialized value $1 in concatenation (.) or string at zahler2 line 93.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    
    OBIS ID:     56.7.0
    OBIS search: 77070100380700FF
    Use of uninitialized value $1 in concatenation (.) or string at zahler2 line 93.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    
    OBIS ID:     76.7.0
    OBIS search: 770701004C0700FF
    Use of uninitialized value $1 in concatenation (.) or string at zahler2 line 93.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    wiregate:/etc/wiregate/plugin/generic/backup#

    Einen Kommentar schreiben:


  • coolrunnings
    antwortet
    Du musst die OBIS IDs anpassen. Evtl. sendet dein Zähler andere Daten.
    Ändere mal folgende Zeile im Code ab und poste die Rohdaten:

    Code:
    $rawdata =~ m/1B1B1B1B01010101(.*?)B1B1B1/;
    print $rawdata ."\n";

    Einen Kommentar schreiben:


  • mosjka1
    antwortet
    danke für den Code. Beim ausführen bekomme ich folgendes:

    Code:
    wiregate:/etc/wiregate/plugin/generic/backup# perl zahler2
    Step 1 - Collect data
    Step 2 - Reg Exp 1 build dataset
    Step 3 - Analyze data
    
    OBIS ID:     1.8.0
    OBIS search: 77070100010800FF
    found: 6400018201621E52FF56000156AE9301
    check sml status:          Invalid integer bit count [4]
    check sml value time:      Invalid datatype [0]
    check sml unit:            Invalid datatype [0]
    check sml scaler:          Invalid datatype [0]
    check sml value:           Invalid datatype [0]
    check sml value signature: Invalid datatype [0]
    
    OBIS ID:     16.7.0
    OBIS search: 77070100100700FF
    found: 0101621B52FF55000055A701
    check sml status:          [empty]
    check sml value time:      [empty]
    check sml unit:            [27]
    check sml scaler:          [-1]
    check sml value:           [21927]
    check sml value signature: [empty]
    Unit config: [W][g]
    Final value: [2192.7 W]
    GAUGE
    obisname  zaehler_leistung
    value     2192.7
    rrdname   zaehler_leistung_g.rrd
    GA:9/0/1 value:2192.7 DPT:9
    
    OBIS ID:     36.7.0
    OBIS search: 77070100240700FF
    Use of uninitialized value $1 in concatenation (.) or string at zahler2 line 91.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    
    OBIS ID:     56.7.0
    OBIS search: 77070100380700FF
    Use of uninitialized value $1 in concatenation (.) or string at zahler2 line 91.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    
    OBIS ID:     76.7.0
    OBIS search: 770701004C0700FF
    Use of uninitialized value $1 in concatenation (.) or string at zahler2 line 91.
    found: 01
    check sml status:          [empty]
    check sml value time:      error --> data too short
    check sml unit:            error --> data too short
    check sml scaler:          error --> data too short
    check sml value:           error --> data too short
    check sml value signature: error --> data too short
    wiregate:/etc/wiregate/plugin/generic/backup#
    Was läuft da falsch?

    Einen Kommentar schreiben:


  • coolrunnings
    antwortet
    Normalerweise bekommst du per SML Protokoll den aktuellen Zäherstand. Da muss nichts hochgezählt werden.

    Ich hänge mal meine aktuelle Version dran. Ich hatte seinerzeit das PlugIn erweitert, so dass weniger Konfiguration nötig ist.
    Ich muss mir doch mal meinen Account bei sourceforge freischalten lassen, damit der ganze Kram nicht verloren geht

    Außerdem benutze ich kein COUNTER RRD sonder DERIVE. Mit den COUNTER RRDs hatte ich Probleme mit Wertüberläufen.

    Ach ja, das Ganze läuft als Crontab, nicht als wiregate PlugIn.

    Gruß

    Code:
    #!/usr/bin/perl
    #
    # Autor: coolrunnings / www.knx-user-forum.de
    # Based on the PlugIn sml-meter by JuMi2006 / www.knx-user-forum.de
    # knx_write sub: makki / www.knx-user-forum.de
    # Version: 0.2
    # Datum: 03.11.2013
    
    use warnings;
    use strict;
    use Device::SerialPort;
    use feature "switch";
    use EIBConnection;
    use RRDs;
    use Scalar::Util qw(looks_like_number);
    
    #####################################################################
    # define everything here
    my $eib_url = "local:/tmp/eib";     #for local eibd "local:/tmp/eib" for eibd in LAN: "ip:192.168.2.220:6720"
    my $device = "/dev/ttyUSB0";
    my $rrdpath = "/var/www/rrd";
    
    my @obis;
    push @obis,{obis=>"1.8.0",  ga =>"9/0/0", dpt =>  14, rrd_name => "zaehler_verbrauch"}; 
    push @obis,{obis=>"16.7.0", ga =>"9/0/1", dpt =>  9, rrd_name => "zaehler_leistung" };
    push @obis,{obis=>"36.7.0", ga =>"9/0/2", dpt =>  9, rrd_name => "zaehler_leistung_L1"};
    push @obis,{obis=>"56.7.0", ga =>"9/0/3", dpt =>  9, rrd_name => "zaehler_leistung_L2"};
    push @obis,{obis=>"76.7.0", ga =>"9/0/4", dpt =>  9, rrd_name => "zaehler_leistung_L3"};
    my @countermodes = (5,15,60,1440);    #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch)
    my @derivemodes = (5,15,60,1440);    #Aufloesungen fuer DERIVE RRDs in Minuten (1440 = Tagesverbrauch)
    
    my $debug   = "1";
    my $logging = "1";
    my $port = Device::SerialPort->new($device) || die $!;
    $port->databits(8);
    $port->baudrate(9600);
    $port->parity("none");
    $port->stopbits(1);
    $port->handshake("none");
    $port->write_settings;
    $port->dtr_active(1);
    $port->purge_all();
    $port->read_char_time(0);     # don't wait for each character
    $port->read_const_time(2000); # 1 second per unfulfilled "read" call
    
    #####################################################################
    # don't touch anything after this point
    
    my $filename = "/tmp/sml_meter.log";
    if ( $logging == "1" ) {open (LOG, ">>$filename") or $logging = "0";}
    
    if ( $logging == "1" ) {print LOG "===============================================\n";}
    if ( $logging == "1" ) {print LOG (localtime)." Start new run\n";}
    
    
    my ($x,$rawdata) = 0 ;
    my $count = 0;
    my $saw = 0;
    my $start = 0;
    
    if ($debug == 1) {print "Step 1 - Collect data \n";}
    if ($logging == 1) {print LOG "Step 1 - Collect data \n";}
    
    while ($start < 2) {	# wait for second 1B1B1B1B01010101
       
    	($count,$saw)=$port->read(512);  # will read 512 chars
    	if ($count == 512) {       		# 512 chars read?
    		$x = uc(unpack('H*',$saw)); # nach hex wandeln
    		$rawdata .= $x;
    		if ($rawdata =~ /1B1B1B1B01010101/)  {$start ++};
    	} # if
    }  # while
    
    if ($debug==1) {print "Step 2 - Reg Exp 1 build dataset \n";}
    if ($logging==1) {print LOG "Step 2 - Reg Exp 1 build dataset \n";}
    
    $rawdata =~ m/1B1B1B1B01010101(.*?)B1B1B1/;
    #print $rawdata ."\n";
    
    if ($debug==1) {print "Step 3 - Analyze data \n";}
    if ($logging==1) {print LOG "Step 3 - Analyze data \n";}
    
    # find OBIS values in raw data
    foreach my $obiscnt (@obis) {
    	if ( $debug == 1 ) {print "\n";}
    	if ( $logging == 1 ) {print LOG "-----------------------------------------------\n";}
    	my $obissearch = &obis2search($obiscnt->{obis});
    	
    	$rawdata =~ m/$obissearch(.*?)017707/;
    	my $obisdata = $1."01";
    	
    	print "found: ".$obisdata."\n";
    	
    	my $smlStatus  = "";
    	my $smlValTime = "";
    	my $smlUnit    = "";
    	my $smlScaler  = "";
    	my $smlValue   = "";
    	my $smlValueS  = "";
    	
    	## check status
    	if ( $debug == 1 ) {print "check sml status:          ";}
    	if ( $logging == 1 ) {print LOG "check sml status:          ";}
    	$smlStatus = &parseOBIS(\$obisdata);
    	
    	## check value time
    	if ( $debug == 1 ) {print "check sml value time:      ";}
    	if ( $logging == 1 ) {print LOG "check sml value time:      ";}
    	$smlValTime = &parseOBIS(\$obisdata);
    	
    	## check unit
    	if ( $debug == 1 ) {print "check sml unit:            ";}
    	if ( $logging == 1 ) {print LOG "check sml unit:            ";}
    	$smlUnit = &parseOBIS(\$obisdata);
    	
    	## check scaler
    	if ( $debug == 1 ) {print "check sml scaler:          ";}
    	if ( $logging == 1 ) {print LOG "check sml scaler:          ";}
    	$smlScaler = &parseOBIS(\$obisdata);
    	
    	## check value
    	if ( $debug == 1 ) {print "check sml value:           ";}
    	if ( $logging == 1 ) {print LOG "check sml value:           ";}
    	$smlValue = &parseOBIS(\$obisdata);
    	
    	## check value signature
    	if ( $debug == 1 ) {print "check sml value signature: ";}
    	if ( $logging == 1 ) {print LOG "check sml value signature: ";}
    	$smlValueS = &parseOBIS(\$obisdata);
    
    	#print "done: ".$obisdata."\n";
    	#print  $smlStatus;
    	
    	# Calculate value
    	if ( $smlValue ne "" ) {
    		my $calcvalue  = ($smlValue * (10**$smlScaler));
    		
    		# Modify value depening on unit
    		my $smlUnitCfg_ref = &getSMLUnitStr($smlUnit);
    		my @smlUnitCfg = @{$smlUnitCfg_ref};
    		
    		if ( (@smlUnitCfg) == 2 ) {
    			my $tUnitStr  = $smlUnitCfg[0];
    			my $tUnitRRD  = $smlUnitCfg[1];
    			
    			# Wh to kWh
    			if ( $smlUnit == 30  ) {
    				$calcvalue = $calcvalue * 0.001;
    				$tUnitStr  = "kWh";
    			}
    			
    			if ( $debug == 1 ) {print "Unit config: [".$tUnitStr."][".$tUnitRRD."]\n";}
    			if ( $logging == 1 ) {print LOG "Unit config: [".$tUnitStr."][".$tUnitRRD."]\n";}
    			
    			if ( $debug == 1 ) {print "Final value: [".$calcvalue." ".$tUnitStr."]\n";}
    			if ( $logging == 1 ) {print LOG "Final value: [".$calcvalue." ".$tUnitStr."]\n";}
    		
    			# write rrd
    			if ($tUnitRRD =~ m/c/) {
    				&rrd_counter ($obiscnt->{rrd_name},$calcvalue)
    			}
    			
    			if ($tUnitRRD =~ m/d/) {
    				&rrd_derive ($obiscnt->{rrd_name},$calcvalue)
    			}
    			
    			if ($tUnitRRD =~ m/g/) {
    				&rrd_gauge ($obiscnt->{rrd_name},$calcvalue)
    			}
    
    			# send value to bus
    			&knx_write ($obiscnt->{ga},$calcvalue,$obiscnt->{dpt});
    			if ($debug == 1) {print "GA:".$obiscnt->{ga}." value:".$calcvalue." DPT:".$obiscnt->{dpt}."\n";}
    			if ($logging == 1) {print LOG "GA:".$obiscnt->{ga}." value:".$calcvalue." DPT:".$obiscnt->{dpt}."\n";}
    				
    				
    		}
    		else {
    			if ( $debug == 1 ) {print "No unit found. No data will be written.\n";}
    			if ( $logging == 1 ) {print LOG "No unit found. No data will be written.\n";}
    		}
    	}	
    }
    
    $port->close() || warn "Serial port did not close proper!\n";
    undef $port;
    
    if ( $logging == "1" ) {close LOG;}
    
    ## subs ##
    
    #####################################################################
    # convert OBIS to search parameter
    sub obis2search {
    
    	my ($obisid) = @_;
    	my $res = "77070100";
    	
    	if ($debug==1) { print "OBIS ID:     ".$obisid."\n";}
    	if ($logging==1) { print LOG "OBIS ID:     ".$obisid."\n";}
    		
    	foreach my $c ( split(/\./,$obisid) ) {
    		$res .= sprintf("%02X",$c);
    	}
    	
    	$res .= "FF";
    	
    	if ($debug==1) { print "OBIS search: ".$res."\n";}
    	if ($logging==1) { print LOG "OBIS search: ".$res."\n";}
    	
    	return $res;
    }
    
    #####################################################################
    # parse OBIS data
    sub parseOBIS {
    	#my ($obisdata) = @_;
    	my $r_obisdata = shift;
    	my $res = "";
    	
    	if ( length($$r_obisdata) < 2 ) {
    		print "error --> data too short\n";
    		return $res;
    	}
    	
    	my $smlDataTypeID = substr($$r_obisdata,0,2); 
    	
    	if ( $smlDataTypeID == "01" ) {
    		## no data
    		if ( $debug == 1 ) {print "[empty]\n";}
    		if ( $logging == 1 ) {print LOG "[empty]\n";}
    		$$r_obisdata =~ s/^..//;	# remove first 2 characters
    		return $res;
    	}
    	else {
    		#if ( $debug == 1 ) {print "found something ";}
    		#if ( $logging == 1 ) {print LOG "found something ";}
    		
    		my $smlDataType    = substr($smlDataTypeID,0,1);
    		my $smlIntBitCode = substr($smlDataTypeID,1,1);
    		
    		# only signed and unsigned int possible
    		if ( $smlDataType != "5" && $smlDataType != "6") {
    			if ( $debug == 1 ) {print "Invalid datatype [".$smlDataType."]\n"; };
    			if ( $logging == 1 ) {print LOG "Invalid datatype [".$smlDataType."]\n"; };
    			return $res;
    		}
    		
    		$$r_obisdata =~ s/^..//;	# remove first 2 characters
    		
    		
    		my $smlIntBitCnt = 0;
    		
    		#switch ( $smlIntBitCode ) {
    		#	case 2	{ $smlIntBitCnt =  8 }
    		#	case 3	{ $smlIntBitCnt = 16 }
    		#	case 5	{ $smlIntBitCnt = 32 }
    		#	case 9	{ $smlIntBitCnt = 64 }
    		#	else  	{ if ( $debug == 1 ) {print "Invalid integer bit count [".$smlIntBitCode."]\n"; };
    		#			  return $res; 
    		#			}
    		#}
    		
    		if ( $smlIntBitCode == 2 ) {
    			$smlIntBitCnt =  8
    		}
    		elsif ( $smlIntBitCode == 3 ) {
    			$smlIntBitCnt =  16
    		}
    		elsif ( $smlIntBitCode == 5 ) {
    			$smlIntBitCnt =  32
    		}
    		elsif ( $smlIntBitCode == 9 ) {
    			$smlIntBitCnt =  64
    		}
    		else {
    			if ( $debug == 1 ) {print "Invalid integer bit count [".$smlIntBitCode."]\n"; };
    			if ( $logging == 1 ) {print LOG "Invalid integer bit count [".$smlIntBitCode."]\n"; };
    			return $res;
    		}
    		
    		my $smlIntCharCnt = ($smlIntBitCnt/4);
    		
    		# check that the rest of the string is long enought for the bit count
    		if ( (length($$r_obisdata)) < $smlIntCharCnt ) {
    			if ( $debug == 1 ) {print "String not long enough for for detected bit count [".$smlIntCharCnt."]\n"; };
    			if ( $logging == 1 ) {print LOG "String not long enough for for detected bit count [".$smlIntCharCnt."]\n"; };
    			return $res;
    		}
    		
    		# get the hex values
    		my $hexval = substr($$r_obisdata,0,$smlIntCharCnt);
    		$$r_obisdata = substr($$r_obisdata,$smlIntCharCnt);
    		
    		# if signed, get 2' complement
    		if ( $smlDataType == 5 ) {
    			my $hexbin = sprintf("%0${smlIntBitCnt}b",hex($hexval));
    		
    			if ( substr($hexbin,0,1) == 1 ) {
    				#if ( $debug == 1 ) { print "2's complement \n"; }
    				#if ( $logging == 1 ) { print LOG "2's complement \n"; }
    				my $hexinv = sprintf("%08x",~hex($hexval));
    				$res = (substr($hexinv,6,2)+1)*(-1);
    			
    			}
    			else {
    				$res = hex($hexval);
    			}
    		}
    		else {
    			$res = hex($hexval);
    		}
    		
    		if ( $debug == 1 ) { print "[".$res."]\n";}
    		if ( $logging == 1 ) { print LOG "[".$res."]\n";}
    		
    		return $res;
    	}
    	
    	return $res;
    }
    
    #####################################################################
    # get SML unit string depending on value
    # DLMS Units as specified in ISO EN 62056-62 and used by SML
    # original values from unit.h in vzlogger project
    # The volkszaehler.org project
    sub getSMLUnitStr {
    
    	my ($smlUnitCode) = @_;
    	
    	my %unitmap = (	
    	# code	  # unit		#rrd		# quantity						#name					#SI definition
    	
    	1 => 	[ "a",			"g" ],      # time                			year            		52*7*24*60*60 s
    	2 => 	[ "mo",			"g" ],      # time                			month            		31*24*60*60 s
    	3 => 	[ "wk",			"g" ],      # time                			week            		7*24*60*60 s
    	4 => 	[ "d",			"g" ],      # time                			day            			24*60*60 s
    	5 => 	[ "h",			"g" ],      # time                			hour            		60*60 s
    	6 => 	[ "min.",		"g" ],      # time                			min            			60 s
    	7 => 	[ "s",			"g" ],      # time (t)            			second            		s
    	8 => 	[ "°",			"g" ],      # (phase) angle        			degree            		rad*180/π
    	9 => 	[ "°C",			"g" ],      # temperature (T)       		degree celsius      	K-273.15
    	10 => 	[ "currency",	"g" ],    	# (local) currency
    	11 => 	[ "m",			"g" ],      # length (l)            		metre            		m
    	12 => 	[ "m/s",		"g" ],      # speed (v)            			metre per second    	m/s
    	13 => 	[ "m³",			"g" ],      # volume (V)            		cubic metre        		m³
    	14 => 	[ "m³",			"g" ],      # corrected volume      		cubic metre        		m³
    	15 => 	[ "m³/h",		"g" ],      # volume flux           		cubic metre per hour    m³/(60*60s)
    	16 => 	[ "m³/h",		"g" ],      # corrected volume flux 		cubic metre per hour    m³/(60*60s)
    	17 => 	[ "m³/d",		"g" ],      # volume flux                        					m³/(24*60*60s)
    	18 => 	[ "m³/d",		"g" ],      # corrected volume flux                					m³/(24*60*60s)
    	19 => 	[ "l",			"g" ],      # volume            			litre            		10-3 m³
    	20 => 	[ "kg",			"g" ],      # mass (m)            			kilogram
    	21 => 	[ "N",			"g" ],      # force (F)            			newton
    	22 => 	[ "Nm",			"g" ],      # energy            			newtonmeter        		J = Nm = Ws
    	23 => 	[ "Pa",			"g" ],      # pressure (p)          		pascal            		N/m²
    	24 => 	[ "bar",		"g" ],      # pressure (p)          		bar            			10⁵ N/m²
    	25 => 	[ "J",			"g" ],      # energy            			joule            		J = Nm = Ws
    	26 => 	[ "J/h",		"g" ],      # thermal power        			joule per hour        	J/(60*60s)
    	27 => 	[ "W",			"g" ],      # active power (P)      		watt            		W = J/s
    	28 => 	[ "VA",			"g" ],      # apparent power (S)    		volt-ampere
    	29 => 	[ "var",		"g" ],      # reactive power (Q)    		var
    	30 => 	[ "Wh",			"cdg" ],    # active energy        			watt-hour        		W*(60*60s)
    	31 => 	[ "VAh",		"g" ],      # apparent energy       		volt-ampere-hour    	VA*(60*60s)
    	32 => 	[ "varh",		"g" ],      # reactive energy       		var-hour        		var*(60*60s)
    	33 => 	[ "A",			"g" ],      # current (I)           		ampere            		A
    	34 => 	[ "C",			"g" ],      # electrical charge (Q) 		coulomb            		C = As
    	35 => 	[ "V",			"g" ],      # voltage (U)           		volt            		V
    	36 => 	[ "V/m",		"g" ],      # electr. field strength (E)    volt per metre
    	37 => 	[ "F",			"g" ],      # capacitance (C)       		farad            		C/V = As/V
    	38 => 	[ "Ω",			"g" ],      # resistance (R)        		ohm            			Ω = V/A
    	39 => 	[ "Ωm²/m",		"g" ],      # resistivity (ρ)       		Ωm
    	40 => 	[ "Wb",			"g" ],      # magnetic flux (Φ)     		weber            		Wb = Vs
    	41 => 	[ "T",			"g" ],      # magnetic flux density (B)    	tesla            		Wb/m2
    	42 => 	[ "A/m",		"g" ],      # magnetic field strength (H)   ampere per metre    	A/m
    	43 => 	[ "H",			"g" ],      # inductance (L)        		henry            		H = Wb/A
    	44 => 	[ "Hz",			"g" ],      # frequency (f => ω)        	hertz            		1/s
    	45 => 	[ "1/(Wh)",		"g" ],      # R_W                           (Active energy meter constant or pulse value)
    	46 => 	[ "1/(varh)",	"g" ],     	# R_B                           (reactive energy meter constant or pulse value)
    	47 => 	[ "1/(VAh)",	"g" ],    	# R_S                           (apparent energy meter constant or pulse value)
    	48 => 	[ "V²h",		"g" ],      # volt-squared hour        	´	volt-squaredhours    	V²(60*60s)
    	49 => 	[ "A²h",		"g" ],      # ampere-squared hour        	ampere-squaredhours    	A²(60*60s)
    	50 => 	[ "kg/s",		"g" ],      # mass flux            			kilogram per second    	kg/s
    	51 => 	[ "S => mho",	"g" ],     	# conductance siemens                    				1/Ω
    	52 => 	[ "K",			"g" ],     	# temperature (T)        		kelvin
    	53 => 	[ "1/(V²h)",	"g" ],    	# R_U²h                        (Volt-squared hour meter constant or pulse value)
    	54 => 	[ "1/(A²h)",	"g" ],    	# R_I²h                        (Ampere-squared hour meter constant or pulse value)
    	55 => 	[ "1/m³",		"g" ],      # R_V => meter constant or pulse value (volume)
    	56 => 	[ "%",			"g" ],      # percentage            		%
    	57 => 	[ "Ah",			"g" ],      # ampere-hours            		ampere-hour
    	60 => 	[ "Wh/m³",		"g" ],      # energy per volume                    					3,6*103 J/m³
    	61 => 	[ "J/m³",		"g" ],      # calorific value, wobbe
    	62 => 	[ "Mol %",		"g" ],      # molar fraction of        		mole percent    (Basic gas composition unit)
    										# gas composition  
    	63 => 	[ "g/m³",		"g" ],      # mass density, quantity of material            (Gas analysis => accompanying elements)
    	64 => 	[ "Pa s",		"g" ],      # dynamic viscosity pascal second       		(Characteristic of gas stream)
    	253 => 	[ "(reserved)",	"g"],		# reserved
    	254 => 	[ "(other)",	"g" ],    	# other unit
    	255 => 	[ "(unitless)",	"g"]   	# no unit, unitless, count
    	);
    	
    	#print "-------- unit ".$unitmap{$smlUnitCode}[0]."\n";
    	
    	#print "-------- unit ".$unitmap{$smlUnitCode}."\n";
    	
    	my $unitarray_ref = $unitmap{$smlUnitCode};
    	
    	return $unitarray_ref;
    	
    }
    
    #####################################################################
    
    sub knx_write {
        my ($dst,$value,$dpt,$response,$dbgmsg) = @_;
        my $bytes;
        my $apci = ($response) ? 0x40 : 0x80; # 0x40=response, 0x80=write
        #     DPT 1 (1 bit) = EIS 1/7 (move=DPT 1.8, step=DPT 1.7)
        #     DPT 2 (1 bit controlled) = EIS 8
        #     DPT 3 (3 bit controlled) = EIS 2
        #     DPT 4 (Character) = EIS 13
        #     DPT 5 (8 bit unsigned value) = EIS 6 (DPT 5.1) oder EIS 14.001 (DPT 5.10)
        #     DPT 6 (8 bit signed value) = EIS 14.000
        #     DPT 7 (2 byte unsigned value) = EIS 10.000
        #     DPT 8 (2 byte signed value) = EIS 10.001
        #     DPT 9 (2 byte float value) = EIS 5
        #     DPT 10 (Time) = EIS 3
        #     DPT 11 (Date) = EIS 4
        #     DPT 12 (4 byte unsigned value) = EIS 11.000
        #     DPT 13 (4 byte signed value) = EIS 11.001
        #     DPT 14 (4 byte float value) = EIS 9
        #     DPT 15 (Entrance access) = EIS 12
        #     DPT 16 (Character string) = EIS 15
        # $dpt = $eibgaconf{$dst}{'DPTSubId'} unless $dpt; # read dpt from eibgaconf if existing
        given ($dpt) {
            when (/^12/)             { $bytes = pack ("CCL>", 0, $apci, $value); }  #EIS11.000/DPT12 (4 byte unsigned)
            when (/^13/)             { $bytes = pack ("CCl>", 0, $apci, $value); }
            when (/^14/)             { $bytes = pack ("CCf>", 0, $apci, $value); }
            when (/^16/)             { $bytes = pack ("CCa14", 0, $apci, $value); }
            when (/^17/)             { $bytes = pack ("CCC", 0, $apci, $value & 0x3F); }
            when (/^20/)             { $bytes = pack ("CCC", 0, $apci, $value); }
            when (/^\d\d/)           { return; } # other DPT XX 15 are unhandled
            when (/^[1,2,3]/)        { $bytes = pack ("CC", 0, $apci | ($value & 0x3f)); } #send 6bit small
            when (/^4/)              { $bytes = pack ("CCc", 0, $apci, ord($value)); }
            when ([5,5.001])         { $bytes = pack ("CCC", 0, $apci, encode_dpt5($value)); } #EIS 6/DPT5.001 1byte
            when ([5.004,5.005,5.010]) { $bytes = pack ("CCC", 0, $apci, $value); }
            when (/^5/)              { $bytes = pack ("CCC", 0, $apci, $value); }
            when (/^6/)              { $bytes = pack ("CCc", 0, $apci, $value); }
            when (/^7/)              { $bytes = pack ("CCS>", 0, $apci, $value); }
            when (/^8/)              { $bytes = pack ("CCs>", 0, $apci, $value); }
            when (/^9/)              { $bytes = pack ("CCCC", 0, $apci, encode_dpt9($value)); } #EIS5/DPT9 2byte float
            default                  { LOGGER('WARN',"None or unsupported DPT: $dpt sent to $dst value $value"); return; }
        }
        my $leibcon = EIBConnection->EIBSocketURL($eib_url) or return("Error opening con: $!");
        if ($leibcon->EIBOpenT_Group(str2addr($dst),1) == -1) { return("Error opening group: $!"); }
        my $res=$leibcon->EIBSendAPDU($bytes);
        $leibcon->EIBClose();
        return $res;
        
        # str2addr: Convert an EIB address string in the form "1/2/3" or "1.2.3" to an integer
        sub str2addr {
            my $str = $_[0];
            if ($str =~ /(\d+)\/(\d+)\/(\d+)/) { # logical address
                return ($1 << 11) | ($2 << 8) | $3;
            } elsif ($str =~ /(\d+)\.(\d+)\.(\d+)/) { # physical address
                return ($1 << 12) | ($2 << 8) | $3;
            } else {
                #bad
                return;
            }
        }
        
    }
    
    #####################################################################
    
    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;
    }
    
    #####################################################################
    
    sub rrd_counter
    {
        if ($debug==1){print ("COUNTER","\n")};
    	if ($logging==1){print LOG ("-- COUNTER ---","\n")};
    	
    	my $obisname = $_[0];
    	if ($debug==1){print "obisname  ".$obisname."\n";}
    	if ($logging==1){print LOG "obisname  ".$obisname."\n";}
    	my $value = $_[1];
        if ($debug==1){print "value     ".$value."\n";}
    	if ($logging==1){print LOG "value     ".$value."\n";}
        
        foreach (@countermodes)
        {
            my $rrdname = $obisname."_".$_."_c\.rrd";
            if ($debug==1){print "rrdname   ".$rrdname."\n"};
    		if ($logging==1){print LOG "----------\n"};
    		if ($logging==1){print LOG "rrdname   ".$rrdname."\n"};
            my $rrdfile = $rrdpath."\/".$rrdname;
            unless (-e $rrdfile)
            {
                RRDs::create ($rrdfile,"DS:value:COUNTER:".(($_*60)+600).":0:U",
    			"RRA:AVERAGE:0.5:1:366",	
    			"RRA:AVERAGE:0.5:7:1308",
    			"-s ".($_*60));				# step 
            }
            my $countervalue = int($value*$_*60);
    		if ($debug==1){print "[".$value."]*[".$_."]*[60] = ".$countervalue." countervalue \n";}
    		if ($logging==1){print LOG "[".$value."]*[".$_."]*[60] = ".$countervalue." countervalue \n";}
            RRDs::update("$rrdfile", "N:$countervalue");
        }
    }
    
    sub rrd_derive
    {
        if ($debug==1){print ("DERIVE","\n")};
    	if ($logging==1){print LOG ("-- DERIVE ---","\n")};
    	
    	my $obisname = $_[0];
    	if ($debug==1){print "obisname  ".$obisname."\n";}
    	if ($logging==1){print LOG "obisname  ".$obisname."\n";}
    	my $value = $_[1];
        if ($debug==1){print "value     ".$value."\n";}
    	if ($logging==1){print LOG "value     ".$value."\n";}
        
        foreach (@derivemodes)
        {
            my $rrdname = $obisname."_".$_."_d\.rrd";
            if ($debug==1){print "rrdname   ".$rrdname."\n"};
    		if ($logging==1){print LOG "----------\n"};
    		if ($logging==1){print LOG "rrdname   ".$rrdname."\n"};
            my $rrdfile = $rrdpath."\/".$rrdname;
            unless (-e $rrdfile)
            {
                RRDs::create ($rrdfile,"DS:value:DERIVE:".(($_*60)+600).":0:U",
    			"RRA:AVERAGE:0.5:1:366",	
    			"RRA:AVERAGE:0.5:7:1308",
    			"-s ".($_*60));				# step 
            }
            my $derivevalue = int($value*$_*60);
    		if ($debug==1){print "[".$value."]*[".$_."]*[60] = ".$derivevalue." derivevalue \n";}
    		if ($logging==1){print LOG "[".$value."]*[".$_."]*[60] = ".$derivevalue." derivevalue \n";}
            RRDs::update("$rrdfile", "N:$derivevalue");
        }
    }
    
    #####################################################################
    
    sub rrd_gauge
    {
        if ($debug==1){print ("GAUGE","\n")};
    	if ($logging==1){print LOG ("-- GAUGE --","\n")};
        my $obisname = $_[0];
        if ($debug==1){print "obisname  ".$obisname."\n";}
    	if ($logging==1){print LOG "obisname  ".$obisname."\n";}
    	my $value = $_[1];
        if ($debug==1){print "value     ".$value."\n";}
    	if ($logging==1){print LOG "value     ".$value."\n";}
        my $rrdname = $obisname."_g\.rrd";
        if ($debug==1){print "rrdname   ".$rrdname."\n"};
    	if ($logging==1){print LOG "rrdname   ".$rrdname."\n"};
        my $rrdfile = $rrdpath."\/".$rrdname;
        unless (-e $rrdfile)
        {
            RRDs::create ($rrdfile,"DS:value:GAUGE:900:0:U",
    		"RRA:AVERAGE:0.5:1:2016",		# 5 minutes for 7 days
    		"RRA:AVERAGE:0.5:6:1488",		# 30 minutes for 31 days
    		"RRA:AVERAGE:0.5:12:4392",		# 1 hour for 5 month
    		"RRA:AVERAGE:0.5:72:7320",		# 6 hours for 5 years
    		"RRA:AVERAGE:0.5:2016:1308");	# 1 day for 25 years	
        }
        RRDs::update("$rrdfile", "N:$value");
    }

    Einen Kommentar schreiben:


  • mosjka1
    antwortet
    Zitat von JuMi2006 Beitrag anzeigen
    Versuchs mal hiermit....klingt nach SML-Protokoll, oder den Thread mal nach SML durchsuchen.

    Open Automation / Code / [r1702] /tools/sml-meter/sml_meter.pl
    Dieses Plugin funktioniert mit dem volkszaehler ir-lesekopf super! Wo in dem Code muss ich meinen aktuellen Zählerstand eintragen, damit der Counter diesen dann hoch zählt?

    Danke

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    So ... da isses: https://knx-user-forum.de/352354-post88.html

    Einen Kommentar schreiben:


  • JuMi2006
    antwortet
    Irgendwo war da mal was ... sieh Dir doch mal die RRDs mit rrdtool fetch an.

    Einen Kommentar schreiben:


  • nipponichi
    antwortet
    Es scheint, daß je nach Granularität bei rrd_counter ein zeitlicher Versatz auftritt, z.B. hier bei 5 und 60 Minuten. Liegt das an der Anlage der rrd-Datei oder an der Anzeige?
    Angehängte Dateien

    Einen Kommentar schreiben:

Lädt...
X