Klick mal das Display an Deinem Zähler durch ob er 15.7.0 oder 0.7.0/7.0 überhaupt ausgibt. Da sind die Zähler je nach EVU eingeschränkt. Mein Zähler für die WP gibt die aktuelle Leistung zwar im Display aber nicht über die Schnittstelle aus.
Sonst muss man mal gucken was der Zäher im Rohformat ausspuckt. Dazu die folgende Zeile wieder aktivieren:
Open Automation / Code / [r1961] /tools/sml-meter/sml_meter.pl
Output posten.
Ankündigung
Einklappen
Keine Ankündigung bisher.
Zählerabfrage als Wiregate Plugin
Einklappen
Dieses Thema ist geschlossen.
X
X
-
Dann mach ich mal hier weiter (org. Post).
Meine Konfig sieht folgendermaßen aus:
Code:my @obis; push @obis,{obis=>"1.8.0", fact=>10000, ga =>"9/0/0", dpt => 14, rrd_name => "Zaehler_Verbrauch", rrd => "c" }; #rrd: c=counter ; g=gauge push @obis,{obis=>"15.7.0", fact=>10, ga =>"9/0/1", dpt => 9 , rrd_name => "Zaehler_Leistung", rrd => "g" }; my @countermodes = (5,15,60,1440); #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch) my $debug = "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
Die Werte für die OBIS Daten habe ich hier her: volkszaehler.org
Einen Kommentar schreiben:
-
AW: Zählerabfrage als Wiregate Plugin
Was soll ich sagen. Funktioniert nach wie vor super. Daher Danke noch mal ab dieser Stelle für die super Unterstützung. Ab und an hakt es lediglich in der Hinsicht, dass im rrd ein unrealistischer Wert angezeigt wird (z.b. Tausender kWh) Woher der Ausreißer kommt kann ich noch nicht sagen.
Gibt es eigentlich auch eine Möglichkeit neben den absoluten Werten im rrd auch parallel den Durchschnittswert anzeigen zu lassen?
Grüße,
mike
Gesendet von meinem Z10 mit Tapatalk 2
Einen Kommentar schreiben:
-
Hallo
Ich habe ein Q3C.
Der Q3C hat oben auf den Zähler auch eine optische Schnittstelle.
Die Schnittstelle sendet alle paar sek. die Daten automtisch.
Ich habe dort den Auslesekopf von Udo (Volkszähler) installiert.
Die Daten lesen ich mit einen sh-Script aus das sh.Script wird mit cron jede Minute gestartet, es startet dann ein Perl-Script das dann die Daten aus den Zähler ausliest, das sh-Sript überprüft auch ob das Perl-Script noch läuft, wenn ja dann beendet es das Perl-Script.
Hier das Perl-Script:
Code:#!/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 # use Device::SerialPort; use DBI; use RRDs; # in $iso steht Datum-Zeit = 'Y-m-d H:M:S' my @dta = localtime(time); my $iso=($dta[5]+1900)."-"; $iso.=sprintf('%02d-',$dta[4]+1); $iso.=sprintf('%02d ',$dta[3]); $iso.=sprintf('%02d:',$dta[2]); $iso.=sprintf('%02d:',$dta[1]); $iso.=sprintf('%02d',$dta[0]); print "sml_Zaehler " . $iso . "\n"; # my $port = Device::SerialPort->new("/dev/usbserial-AHVPKI8A") || 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 immer 8 Zeichen %obis_len = ( '01010801FF' => 42, # Aktueller Zählerstand T1 + Bezug '02020805FF' => 42, # Aktueller Zählerstand T5 - Abgabe '00010700FF' => 24 # Momentane Summe der Leistung +- ); my $pos = 0; my $hexval; my @hexdec; while ($i < 3) { # 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 == 540) { # wurden 540 chars gelesen ? my $x=uc(unpack('H*',$saw)); # nach hex wandeln print "$count <> $x\n "; # gibt die empfangenen Daten in Hex aus # foreach $key(keys%obis_len){ $pos=index($x,$key); # pos von OBIS holen $value = substr($x,$pos+$obis_len{$key},8); # Messwert $value{$key} = hexstr_to_signed32int($value)/100; # von hex nach 32bit integer } last; # while verlassen } else { $i++; # print "i=" . $i . "\n"; my $x=uc(unpack('H*',$saw)); # nach hex wandeln # print "$count <> $x\n "; # gibt die empfangenen Daten in Hex aus redo; # bei Fehler while nochmal } } $port->close(); # $value = $value{'00010700FF'} * -1; @hexdec = encode_dpt9($value); $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]); system("groupwrite ip:127.0.0.1 5/0/12 $hexval"); # Zaehler Leistung auf KNX print "00010700FF = " . $value . "\n"; # -------------- Ausgabe in DB und RRD -------------------- # DB oeffnen my $dbargs = {AutoCommit => 0, PrintError => 1}; # my $dbh = DBI->connect("dbi:SQLite2:dbname=/var/www/myhouse/sq_lite/myhouse.sqlite", "", "", $dbargs); $dbh->do("UPDATE myhouse SET date_zeit='".$iso."', wert='".$value."' WHERE adr='5/0/12'"); $dbh->commit; # Änderungen auf die Datenbank einfügen @hexdec = encode_dpt9($value{'01010801FF'}); $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]); system("groupwrite ip:127.0.0.1 5/0/13 $hexval"); # $dbh->do("UPDATE myhouse SET date_zeit='".$iso."', wert='".$value{'01010801FF'}."' WHERE adr='5/0/13'"); $dbh->commit; # Änderungen auf die Datenbank einfügen @hexdec = encode_dpt9($value{'02020805FF'}); $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]); system("groupwrite ip:127.0.0.1 5/0/14 $hexval"); # $dbh->do("UPDATE myhouse SET date_zeit='".$iso."', wert='".$value{'02020805FF'}."' WHERE adr='5/0/14'"); $dbh->commit; # Änderungen auf die Datenbank einfügen my $value_rrd = $value{'00010700FF'} * -1; # wert negieren wegen Anzeige in Visu # print "00010700FF = " . $value{'00010700FF'} . "=" . $value_rrd . "\n"; RRDs::update("/var/www/rrd/Zaehler_Leistung.rrd", "N: $value_rrd"); # $dbh->disconnect(); # DB schliessen # # --- Sub Konvertiert hex string to 32 bit signed integer ---------- sub hexstr_to_signed32int { my ($hexstr) = @_; die "Invalid hex string: $hexstr" if $hexstr !~ /^[0-9A-Fa-f]{1,8}$/; my $num = hex($hexstr); return $num >> 31 ? $num - 2 ** 32 : $num; } # --- Sub 2byte signed float -------------------------------------- sub encode_dpt9 { 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; } # Ende
Einen Kommentar schreiben:
-
Ich hab mir Deines jetzt nicht angesehen, konnte mich aber daran das damals mit mike durchgegangen zu sein und fand den Code in meinem Postfach ... hat es dann wohl nie ins SVN geschafft:
Code:#!/usr/bin/perl # Autor: JuMi2006 / www.knx-user-forum.de # knx_write sub: makki / www.knx-user-forum.de # Version: für Mikeyy / www.knx-user-forum.de # Datum: 20.02.2013 # Ein Zähler nach IEC 62056 der Werte von 2 Zählern übermittelt und ähnlich SML selbstständig sendet # INCREDIBLE !!! ;) use warnings; use strict; use Device::SerialPort; use feature "switch"; use EIBConnection; use RRDs; ### KONFIGURATION ### my $eib_url = "local:/tmp/eib"; #for local eibd "local:/tmp/eib" for eibd in LAN: "ip:192.168.2.220:6720" my $rrdpath = "/var/www/rrd"; my $debug = "1"; my $device = "/dev/ttyS0"; #Port my $endsign = "!"; #Letztes Zeichen im Protokoll vom Zaehler my @zaehler = ("1-1","1-0","0-0"); #Auszulesende Zähler my @obis; push @obis,{znr => "0-0", obis=>"17.0.0", ga =>"0/7/200", dpt => 9 , rrd_name => "Name0",}; push @obis,{znr => "1-0", obis=>"1.8.1", ga =>"0/7/201", dpt => 12 , rrd_name => "Name1",}; push @obis,{znr => "1-0", obis=>"1.8.2", ga =>"0/7/202", dpt => 12 , rrd_name => "Name2",}; push @obis,{znr => "1-1", obis=>"1.8.1", ga =>"0/7/203", dpt => 12 , rrd_name => "Name3",}; my @countermodes = (5,15,60,1440); #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch) ### ENDE KONFIGURATION ### ### EINLESEN #my $file = "/root/mike"; #open (IN,'<',$file); #my @data = <IN>; ### 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'; ### AUSLESEN my $STALL_DEFAULT=15; # how many seconds to wait for new input my $timeout=$STALL_DEFAULT; my $chars=0; my $runs = 0; my $buffer=""; while ($runs < 2 or $timeout < 0) { my ($count,$saw)=$port->read(25); # Liest 25 Zeichen je Durchlauf aus if ($count > 0) { $chars+=$count; $buffer.=$saw; #print ("saw: ".$saw."\n"); # Ausgabe der eingelesenen Daten if ($saw =~ /\Q$endsign\E/) # \Q \E entwertet alle Sonderzeichen dazwischen { print "\n Endzeichen war dabei \n"; $runs++; print "\n RUNS = $runs \n"; } } else { $timeout--; } if ($timeout<=0) { print "Waited $STALL_DEFAULT seconds and never saw what I wanted\n"; last;} } $port->close || die "can't close $device: $!"; #$buffer =~ m/$endsign(.*?)$endsign/; $buffer =~ /($endsign(.*?)$endsign)/s; $buffer = $1; if ($debug==1){print $buffer."\n\n\n"}; #Nur zur Kontrolle my @data = split(/\r?\n/,$buffer); ############ ### MAIN ### ############ foreach my $line (@data){ chomp $line; foreach my $obis (@obis){ if ($line =~ m/$obis->{obis}/ && $line =~ m/$obis->{znr}/){ chomp $line; $line =~ m/[^(]+\(([^*]+)\*([^)]+)/; my $val = $1; my $unit = $2; if ($debug==1){print "Zähler $obis->{znr} Kennzahl $obis->{obis} Wert: $val $unit. \n"}; #RRDS if ($unit =~ /\Qh\E/) { &rrd_counter ($obis->{rrd_name},$val) } else { &rrd_gauge ($obis->{rrd_name},$val) } #KNX &knx_write ($obis->{ga},$val,$obis->{dpt}); if ($debug==1){print "GA:".$obis->{ga}." Wert:".$val." DPT:".$obis->{dpt}."\n"}; } } } ### SUBS ### sub rrd_counter { if ($debug==1){print ("COUNTER","\n")}; foreach (@countermodes) { my $obisname = $_[0]; if ($debug==1){print $obisname." obisname \n";} my $value = $_[1]; if ($debug==1){print $value." value \n";} my $rrdname = $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]; if ($debug==1){print $obisname." obisname \n";} my $value = $_[1]; if ($debug==1){print $value." value \n";} my $rrdname = $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 { 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; }
Einen Kommentar schreiben:
-
Ich habe mir nun auf Basis des iec62056-meter.pl und den bisherigen Anmerkungen angefügtes Script erstellt. Im Wesentlichen wird nun keine Anfrage mehr gestellt, sondern einfach die Ausgabe des Ports überwacht (bis die Zählerausgabe vollständig ist). Die obis Auswertung musste ich auch etwas anpassen.
Scheint soweit zu funktionieren. Vielleicht hilft es ja jemandem.Angehängte Dateien
Einen Kommentar schreiben:
-
Edit: Unsinn.
Irgendwo hattn wir das schonmal...glaube ich.
Einen Kommentar schreiben:
-
Nachdem das Auslesen meines AS1440 mittlerweile seit über einem halben Jahr gut funktioniert (wiregate mit iec62056-meter.pl, Schreib-/Lesekopf von Udo), möchte ich nun auch den zweiten Zähler auslesen. An dieser Stelle auch nochmals vielen Dank an alle, die viel Mühe in die Skripte gesteckt haben! Natürlich auch an Udo, der einen top Service mit dem Schreib-/Lesekopf bietet!
Der zweite Zähler ist ein EasyMeter Q3D, der über d0 alle 2 Sekunden die Zählerdaten ausspuckt. Über socat erhalte ich folgenden output:
Code:# socat -T 2 - /dev/ttyUSBemq3d,raw,echo=0,b9600,parenb=1,parodd=0,cs7,cstopb=0 /ESY5Q3DA1004 V3.03 1-0:0.0.0*255(0273020311841) 1-0:1.8.0*255(00005456.3053911*kWh) 1-0:21.7.255*255(000368.90*W) 1-0:41.7.255*255(000683.57*W) 1-0:61.7.255*255(000150.12*W) 1-0:1.7.255*255(001202.59*W) 1-0:96.5.5*255(82) 0-0:96.1.255*255(1ESY1203001841) ! /ESY5Q3DA1004 V3.03 1-0:0.0.0*255(0273020311841) 1-0:1.8.0*255(00005456.3060598*kWh) 1-0:21.7.255*255(000369.10*W) 1-0:41.7.255*255(000684.44*W) 1-0:61.7.255*255(000150.03*W) 1-0:1.7.255*255(001203.57*W) 1-0:96.5.5*255(82) 0-0:96.1.255*255(1ESY1203001841) !
Letzter Stand scheint Post 272 zu sein. Bevor ich nun von vorne anfange, wollte ich kurz nachhaken, ob es mittlerweile ein funktionierendes Script für d0 mit zyklischem Senden der Zählerdaten gibt???
Einen Kommentar schreiben:
-
Code-Update
Hallo lio,
evtl. ist Dir schon aufgefallen, dass aktuelle Script hat nach längerer Laufzeit ein immer größeres Gap zur echten Anzeige.
Ich hab den Code jetzt mal erweitert. Damit passen die Werte wieder.
Grüße und frohe Ostern
Gunnar
Code:nach sleep $repeat; einfuegen [B] $port->lookclear; $port->purge_all; $port->purge_rx; [/B]
Einen Kommentar schreiben:
-
Nein ...weil mir momentan Motivation fehlt ... und cron durchaus ein legitimes und einfaches Mittel für viele Anwendungen ist.
Einen Kommentar schreiben:
-
Naja FummelPi hab ich jetzt auch mal überhört...
Zusammenfassung:
Bis auf SML (könnte man auf socat umstricken ... ich aber nicht mehr) geht es de facto nicht als Plugin.
Jetzt darf wieder unterschieden werden welches Protokoll der Zähler hat.
- SML (akutell diskutiert) kann man ein kleines Package machen, incl. initscript und Eintrag in die rc. Dann läuft das aktuelle hier einfach als Daemon -> Wenn es im Repo vom WireGate liegt reicht ein "apt-get install sml-hastenichgesehen" im Zweifel ja sogar übers webmin. Dann noch eine configdatei bearbeiten - Fertig.
Davor darf man sich gerne noch über evtl. Abhängigkeiten/Features (monit,logrotate,etc.) unterhalten.
- D0-IEC62056 (egal welche Version) darf/kann wirklich nur als cronjob laufen. Einrichtung übers Webmin < 5 Minuten.
Einen Kommentar schreiben:
-
Guten Morgen,
nix gegen meinen "FummelPi" - ich find ein tolles Spielzeug
Mit dem cron bin ich jetzt ein wenig stutzig. Das aktuelle Skript ist so gebaut, das es einmal gestartet werden muss und dann immer munter rennt. Müsste quasi beim Init vom WG gestartet werden.
Cron geht insofern, da er es nur einmal starten würde. Find ich persönlich aber nicht schön sowas - Optimalerweise müsste man das in das init-Script von linknx (so werde ich es machen) oder WG aufnehmen.
Grüße
Gunnar (mit eibd, linkxn, Luxtronik, ED300L über RasPi am Bus )
Einen Kommentar schreiben:
-
Das wäre schön, mir gehts darum: ein WG-Plugin muss man optimalerweise nur "reinkopieren", wenns nen socat dazu braucht (brauchen meine auch massenweise..) sollte das als Kommentar o.ä. drinstehen, wenns nen crontab-Eintrag bracht, ist ansich nichts wildes, aber sollte dastehen weil das die meisten an Grenzen führt
Und es geht auch in einfach, ich freue mich über jedes wie ein Schnitzel, die Zielgruppe der Plugins waren aber nicht Leute, die es eh checken und sich dann was-auch-immer drumherumbauen..
Makki
Einen Kommentar schreiben:
Einen Kommentar schreiben: