Hi JuMi,
warum wandelst Du die Ausgabe vor der Weiterverarbeitung in HEX um? Bei mir tut es leider nix.. keine Ausgabe..
Grüße,
Mike
Ankündigung
Einklappen
Keine Ankündigung bisher.
Zählerabfrage als Wiregate Plugin
Einklappen
Dieses Thema ist geschlossen.
X
X
-
So ... jetzt auch für SML. Läuft derzeit bei Lio ... er wird berichten.
Das ganze ist KEIN WireGate Plugin sondern ein simples Perl-Script dass über crontab aufgerufen wird.
Grüße
Code:#!/usr/bin/perl # Autor: JuMi2006 / www.knx-user-forum.de # knx_write sub: makki / www.knx-user-forum.de # Version: 0.1 # Datum: 19.02.2013 use warnings; use strict; use Device::SerialPort; use feature "switch"; use EIBConnection; use RRDs; #0701000F0700FF = 7.0 FIXME !!! [0F]0700 #070100010801FF = 1.8.1 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/ttyUSB-1-4"; my $rrdpath = "/var/www/rrd"; my @obis; push @obis,{obis=>"1.8.0", fact=>10000, ga =>"14/8/1", dpt => 14, rrd_name => "Zaehler_Verbrauch", rrd => "c" }; #rrd: c=counter ; g=gauge push @obis,{obis=>"7.0", fact=>10, ga =>"14/8/0", dpt => 9 , rrd_name => "Zaehler_Leistung", rrd => "g" }; my @countermodes = (5,15,60,1440); #Aufloesungen fuer COUNTER RRDs in Minuten (1440 = Tagesverbrauch) my $debug = ""; 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 my ($x,$data); my $start = 0; while ($start < 2) { # wait for second 1B1B1B1B01010101 my ($count,$saw)=$port->read(512); # will read 512 chars if ($count == 512) { # wurden 512 chars gelesen ? $x = uc(unpack('H*',$saw)); # nach hex wandeln $data .= $x; if ($data =~ /1B1B1B1B01010101/){$start ++}; } } $data =~ m/1B1B1B1B01010101(.*?)B1B1B1/; my $sml = $1; #print $1."\n"; foreach my $obis (@obis) { $obis->{obis} =~ s/\./0/g; $obis->{obis} .= "FF"; if ($debug==1){print $obis->{obis}." Obis\n";} $sml =~ m/$obis->{obis}(.*?)0177/; if ($debug==1){print $1." contains hex \n";} my $sml_val = $1; #extract value $sml_val =~ s/^.*52FF//; $sml_val = substr($sml_val,2); print $sml_val." hex \n"; my $value = $sml_val; my $dec_value = sprintf("%d", hex($value)); $dec_value /= $obis->{fact}; print $dec_value."<<<<---- Wert\n"; if ($obis->{rrd} eq "c") { &rrd_counter ($obis->{rrd_name},$dec_value) } if ($obis->{rrd} eq "g") { &rrd_gauge ($obis->{rrd_name},$dec_value) } &knx_write ($obis->{ga},$dec_value,$obis->{dpt}); print "GA:".$obis->{ga}." Wert:".$dec_value." 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:
-
Zitat von makki Beitrag anzeigenWenns wirklich als float rauskommt plädiere ich für int($wert*1000) -> ins RRD /1000
Code:int($wert*rrd_step) -> ins RRD /rrd_step
.
Grüße!
Einen Kommentar schreiben:
-
Also meine ABB bieten mir nur 2 oder 4Byte signed/unsigned int an (DPT 7/8/12/13)
Das Problem mit dem Float im allgemeinen und dem DPT9/14 (IEE754) im speziellen ist das der hoppeln kann, weil er etwas verdichtet (was in der Natur der Sache liegt, weil auch modernste CPUs eigentlich nur INT kennen, FLOAT ist nur eine spielform der Auflösung und Rechen-Methode)
Das muss nicht schlecht sein, ist es auch nicht, aber bei einem Counter mit geringem increment in der dritten Nachkommastelle kann das ziemlich blöd ausgehen.. (Chris M. hatte das mal sehr anschaulich erklärt aber den Beitrag finde ich gerade nicht mehr; Kern der Sache, wenn man den Float als 16/32bit/DPT9/iEEE754, Perl/Python/C 4x rumrechnet können sechs verschiedene Werte rauskommen..)
Wenns wirklich als float rauskommt plädiere ich für int($wert*1000) -> ins RRD /1000
Makki
Einen Kommentar schreiben:
-
Nochmal.
Warum? Wenn der Zählerstand nunmal kein integer ist sondern float - dann behandle ich den auch als float.
Im RRD-tool wird er ja spätestens nach der Multiplikation mit step wieder ein integer. Falls Du das Problem mit dem COUNTER-RRD meinst. Ich wills ja verstehen, aber ich sehe da wirklich keinen Grund.
Btw. selbst ABB nutzt DPT14 für den Zählerstand.
Grüße
Einen Kommentar schreiben:
-
Nochmal, mit Verlaub, DPT9/14 ist für nen Zählerstand ganz einfach falsch..
Das sollte ein integer sein..
Makki
Einen Kommentar schreiben:
-
Im modernen eHz ist der Zählerstand im besten Fall ein float mit der Auflösung von 0.001 kWh. Im schlechtesten Fall hat er eine Auflösung von 0.1 kWh.
Damit bleibt das float und eigentlich kommt da sinnig nur DPT14 raus.
Das DPT9 Müll ist haben wir ja gemerkt.
Grüße
EDIT
Da Frank das neuere script mit den erweiterten DPTs verheiratet hat, kann man sich den DPT ja aussuchen.
Die Version liegt seit gestern im SVN.
Einen Kommentar schreiben:
-
Nur so am Rande, die verwendeten DPTs sind ungeeignet..
Zitat von JuMi2006 Beitrag anzeigen...
ja das liegt am DPT9 ... der ist für sowas zu ungenau. Die RRDs werden glücklicherweise direkt im Plugin erstellt.
Ich hab mein Script auf DPT14 umgestellt, ist allerdings noch nicht im SVN
Das wäre wohl lieber ein DPT7 (unsigned 2Byte/16Bit, Überlauf bei 65.535 beachten) oder DPT12 geworden (unsigned 4Byte/32Bit, Überlauf bei 4.294.967.295 beachten) , oder?
DPT14 (4byte IEEE float ist im Kern genauso ungeeignet, da fällt es nur nicht so schnell auf aber es wird über kurz oder lang zu komischen Phänomenen kommen weil der Zählerstand eine Ganzzahl ist und bleibt..
Makki
Einen Kommentar schreiben:
-
hat doch hier schon ganz gut funktioniert
Code:my $obisvalue=substr($buffer,($pos+length($key)+1),$obis{$key});
Einen Kommentar schreiben:
-
Nur mal kurz zwischendrin:
Code:1-1:1.8.0*255(001216.858*kWh)
1-1
1.8.0
001216.858
kWh
Einen Kommentar schreiben:
-
Zitat von JuMi2006 Beitrag anzeigen
jetzt muss ich gestehen dass ich Deinen Beitrag mit Frank verwechselt habe ... ich erinnere mich wieder ... Sorry
Aber Du hattest zusätzlich noch die "beiden" Zähler in einem oder wie war das?
kein Problem ;-) Bei der Vielzahl von Anfragen hier kann man schon mal den Überblick verlieren.
Ich habe tatsächlich zwei Zähler die gekoppelt sind. Wobei der Zähler mit dem seriellen Anschluss aber auch die Infos vom zweiten Zähler mitliefert.
Siehe auch der Output vom alten Script hier:
0-0:96.1.0*255(050551428442)
1-0:1.8.0*255(003253.186*kWh) -> Zähler 1
1-0:1.8.1*255(000615.455*kWh)
1-0:1.8.2*255(002637.732*kWh)
1-0:2.8.0*255(000000.226*kWh)
1-0:2.8.1*255(000000.226*kWh)
1-0:2.8.2*255(000000.000*kWh)
0-0:96.14.0*255(02)
1-0:15.7.0*255(001360*W)
0-0:17.0.0*255(0085*A)
0-0:96.3.10*255(1)
0-1:96.1.0*255(05055142844)
1-1:1.8.0*255(001216.858*kWh)(13-02-13 09:00:53) -> Zähler 2
1-1:1.8.1*255(001216.859*kWh)(13-02-13 09:00:53)
1-1:1.8.2*255(000000.000*kWh)(13-02-13 09:00:53)
1-1:1.8.3*255(000000.000*kWh)(13-02-13 09:00:53)
1-1:1.8.4*255(000000.000*kWh)(13-02-13 09:00:53)
1-1:2.8.0*255(000000.000*kWh)(13-02-13 09:00:53)
1-1:2.8.1*255(000000.000*kWh)(13-02-13 09:00:53)
1-1:2.8.2*255(000000.000*kWh)(13-02-13 09:00:53)
1-1:2.8.3*255(000000.000*kWh)(13-02-13 09:00:53)
1-1:2.8.4*255(000000.000*kWh)(13-02-13 09:00:53)
0-1:96.14.0*255(01)(13-02-13 09:00:53)
1-1:15.7.0*255(000000*W)(13-02-13 09:00:53)
0-1:17.0.0*255(0000*A)
0-1:96.3.10*255(1)
mit Deinem alten Script bekomme ich bereits alle Daten von beiden Zähler in den $buffer rein. Beispielhaft für Zähler 1 lautet das Ergebnis dann:
Obiskey: 1-0:1.8.1*255(
Position: 83
14
1-0:1.8.1*255: 000617.072 und landet im rrd. Im alten Script gibt es aber die GA Implementierung noch nicht und du hast dort mit $buffer Variablen gearbeitet. Im aktuellen Script dagegen mit @buffer Variablen. Ich kann den Teil für das Auslesen nicht ohne Fehler vom alten Script in das neue Übernehmen. Hier bräuchte ich mal noch einen Denkanstoß.
Grüße,
Mike
Einen Kommentar schreiben:
-
Zitat von mikeeyy Beitrag anzeigenna ja. mein Problem ist ja immer noch, dass mein Zähler alle 10 Sekunden selber sendet...
jetzt muss ich gestehen dass ich Deinen Beitrag mit Frank verwechselt habe ... ich erinnere mich wieder ... Sorry
Aber Du hattest zusätzlich noch die "beiden" Zähler in einem oder wie war das?
Ich hätte da evtl. eine Idee wie das gehen könnte. Man müsste da nur ein paar Zeilen schieben ... Ich versuche das die Tage mal.
Eigentlich müssten wir einfach nur die while-Schleife 2x durchlaufen so dass wir dasCode:if ($buffer =~ /\Q$endsign\E/)
Damit ist gewährleistet dass wir den vollständigen Datensatz erhalten haben. Die Verarbeitung danach ist dann quasi analog zu den neuesten Scripten.
@Frank
Die Probleme waren eher sporadisch, aber gut wenn es geht!
Schieb das doch mal ins SVN wenn es geht ... ich hab nämlich wegen ebus keine Zeit (Lust)
Einen Kommentar schreiben:
-
Jetzt läuft es...
...sogar richtig schnell.
Hallo JuMi,
habe Dein Script von gestern mit der Abfrage aus der 0.1.6 verheiratet und kann meine Daten mit der schnellen Geschwindigkeit aus dem Elster AS1440 auslesen. Er updatet mir jetzt auch am Gesamtstand sofort die erste Kommastelle. Werde das jetzt ne Weile beobachten!
Evtl. verhält sich da mein Zähler etwas anders wie Deiner. Ein Problem mit meinem Auslesekopf (ist der USB Lese- Schreibekopf von volkszaehler.org) konnte ich auch nicht feststellen. Besten Dank nochmals für Deine / eure Unterstützung. Werde mich jetzt mal wieder um die WP (eBus) kümmern
Grüße
Frank
Einen Kommentar schreiben:
-
AW: Zählerabfrage als Wiregate Plugin
na ja. mein Problem ist ja immer noch, dass mein Zähler alle 10 Sekunden selber sendet und das funzt mit der socat Abfrage nicht. die while Schleife im gepostet Script macht das aber perfekt. ohne die werde ich es wohl nicht zum laufen bekommen, denke ich.
Grüße
Mike
Gesendet von meinem GT-P1000 mit Tapatalk 2
Einen Kommentar schreiben:
-
Halt, Stop, Langsam
Ist doch schon alles fertig. Nimm das Script hier:
HIER KLICKEN:
https://knx-user-forum.de/292600-post261.html
Und nur das !!!
Dort passt Du unter Channels DEINE Werte an die Du auslesen möchtest (Schema liegt ja vor). Und trägst noch die richtige Geschwindigkeit, Schnittstelle etc. ein.
Also fasse nur den Bereich bis ### ENDE KONFIGURATION ### an.
Fertig!
Was ist daran so schwierig?
Alles andere ist alter Tobak.
Einen Kommentar schreiben:
Einen Kommentar schreiben: