#!/usr/bin/perl # # Holt die Daten vom SML-Zaehler Easymeter Q3C # es wird die obere optische Schnittstelle ausgelesen # dort liefert der Zaehler alle 2sec. einen Datensatz # wird von CRON jede Minute aufgerufen # http://wiki.volkszaehler.org/software/sml # 03.2012 by NetFritz # 07.2013 by Ollir # ======================================== sub hexstr_to_signed32int { my ($hexstr) = @_; die "Invalid hex string: $hexstr" if $hexstr !~ /^[0-9A-Fa-f]/; #if $hexstr !~ /^[0-9A-Fa-f]{1,8}$/; my $num = hex($hexstr); return $num >> 31 ? $num - 2 ** 32 : $num; } # ======================================== # use Device::SerialPort; my $port = Device::SerialPort->new("/dev/ttyAMA0") || die $!; $port->databits(8); $port->baudrate(9600); $port->parity("none"); $port->stopbits(1); $port->handshake("none"); $port->write_settings; $port->purge_all(); $port->read_char_time(0); # don't wait for each character $port->read_const_time(1000); # 1 second per unfulfilled "read" call # # OBIS-Kennzahl und Anzahl der Zeichen von Anfang OBIS bis Messwert, # Messwertwertlaenge 8-10 Zeichen %channel = ( '56c94300-f188-11e2-aa85-eb712aefabf9' => ['070100010800FF',20,10], # 1-0:1.8.0 /* kWh aufgenommen */ 'dbc081e0-f188-11e2-8e30-3dd74b6c6043' => ['070100020800FF',20,10], # 1-0:2.8.0 /* kWh rueckgespeis*/ 'a301d8d0-903b-1234-94bb-d943d061b6a8' => ['070100100700FF',14,8] # 1-0:16.7.0 /* Wirkleistung aktuell */ ); # von der schnittstelle lesen for($i=0;$i<=5;$i++) { # wenn 540 chars gelesen werden wird mit last # abgebrochen, wenn nicht wird Schleife 2 mal widerholt my ($count,$saw)=$port->read(540); # will read 540 chars if ($count >300) { #print "read $count chars\n"; my $x=uc(unpack('H*',$saw)); # nach hex wandeln # print "$count <> $x\n"; # gibt die empfangenen Daten in Hex aus while (($uuid) = each(%channel)){ $key = $channel{$uuid}[0] ; $pos = $channel{$uuid}[1] ; $len = $channel{$uuid}[2] ; #print "uuid=$uuid , key=$key, pos=$pos, len=$len\n" ; # Stringpos raussuchen $pos1=index($x,$key); # grob rausschneiden $val1 = substr( $x , $pos1 , 50); #print $key . " = " . $val1 . "\n"; # Messwert selber $val2 = substr( $val1 , length($key) + $pos , $len); # Wert umwandeln $val3 = hexstr_to_signed32int($val2)/10; print $uuid . " : " . $val3 . "\n"; # Wert im Hash ablegen $channel{$uuid}[3] = $val3 ; } last; # while verlassen } else { #print "Schnittstellenlesefehler redu = $i ; count = $count <> \n"; } } # ======================================== # Daten per post an den Server senden # http://xmodulo.com/2013/05/how-to-send-http-get-or-post-request-in-perl.html # http://wiki.volkszaehler.org/development/api/reference # das geht: curl -d "" http://localhost/middleware.php/data/5ae94780-ecc7-11e2-91b8-33a3b9ebc717.json?value=24.9 use LWP::UserAgent; $timestamp = time() * 1000 ; # msec seit 1.1.1970 while (($uuid) = each(%channel)){ $val = $channel{$uuid}[3] ; print $uuid . " : " . $timestamp . " : " . $val . "\n"; my $server_endpoint = "http://localhost/middleware.php/data/${uuid}.json?value=" . $val; print "ss=" . $server_endpoint . "\n"; my $ua = LWP::UserAgent->new; # set custom HTTP request header fields my $req = HTTP::Request->new(POST => $server_endpoint); $req->header('content-type' => 'application/json'); $req->header('x-auth-token' => 'kfksj48sdfj4jd9d'); # add POST data to HTTP request body $req->content(" "); my $ua = LWP::UserAgent->new; my $resp = $ua->request($req); if ($resp->is_success) { my $message = $resp->decoded_content; print "Received reply: $message\n"; } else { print "HTTP GET error code: ", $resp->code, "\n"; print "HTTP GET error message: ", $resp->message, "\n"; } }