Ja...ganz vergessen, ich wollte nochmal Danke sagen ;-) !!!
Ich hätte dazu dann gern ein "Counter" rrd ... greentux hatte das mal irgendwo für seinen Pelletkessel, so könnte man schön den Tagesverbrauch sehen. Aber erstmal bin ich froh so weit zu sein.
Als nächstes dann Umschaltung der Auslesegeschwindigkeit, socat und DB-Anbindung und sicherlich eine Berechnung des aktuellen (Verbrauchs 10/30/60 Minuten).
Nun muss ich aber erstmal wieder handwerklich tätig werden.
Also nochmal:
Danke!
P.S.: Bis auf die DPT9 Sub hab ich auch alles verstanden ;-)
Ankündigung
Einklappen
Keine Ankündigung bisher.
Zählerabfrage als Wiregate Plugin
Einklappen
Dieses Thema ist geschlossen.
X
X
-
Hallo
Glückwunsch es geht doch so wie ich es Dir geschrieben habe.
Gruß NetFritz
Einen Kommentar schreiben:
-
So...mein erstes Plugin ;-)
Zählerabfrage für einen EMH-ITZ mit IR-Schreib-/Lesekopf. Hardware habe ich von volkszähler.org und das ganze läuft als Perl-Plugin via cron alle 5 Minuten.
Der Zählerstand wird mit timestamp geloggt, in ein rrd geschrieben und auf den Bus gesendet.
2 kleine Probleme/Fragen noch:
1. Das rrd sieht komisch aus / stimmt nicht -> falsch angelegt !?
2. Der Wert aus dem Log/Konsole (1774,9) stimmt nicht 100% mit dem Bus überein 1774,08) !?
Code:#!/usr/bin/perl # (m)ein Stromzaehler mit IR-Schnittstelle blubbert nach einem "Anforderung- # telegramm" Daten raus. # Das Telegramm ist mit 300 Baud, 7 Bit, 1 Stoppbit # und gerader Parit0t zu senden. Das ist der Initialmodus von Ger0ten, # die das Protokoll IEC 62056-21 implementieren. # Dies betrifft folgende bekannte Zähler: # Das Script ist angepasst auf EMH ITZ. Weitere Zähler wie z.B. Elster AS1440, Siemens TD-3511 müssen # angepasst werden (Position Zählerstand finden). # !!! Wiederholung nur alle 3 Minuten da der Zähler nach Ende des Scriptes weiter sendet !!! # Basis des Scripts von volkszähler.org # Autor: Andreas Schulze # Bugfix: Eric Schanze # Erweiterung um RRD und KNX-Teil auf Wiregate: JuMi2006 # www.knx-user-forum.de # Version: 0.1 # Datum: 02.04.2012 ### KONFIGURATION ### my $PORT='/dev/ttyUSB-1-4'; #Schnittstelle my $anforderungstelegramm = "/?!\r\n"; #Anforderungstelegramm \r\n entspricht CR-LF my $rrd = "/var/www/rrd/Zaehler_WP_abs.rrd"; #rrd-file - muss vorher angelegt werden ! my $file = '/var/tmp/log.txt'; #Logdatei - muss vorher angelegt werden ! my $position = "539"; #Endposition des Zählerstandes im Seneprotokoll my $ga = "0/0/4"; #Gruppenadresse DPT9 ### ENDE KONFIGURATION ### use warnings; use strict; use utf8; use Device::SerialPort; use RRDs; ### Seriellen Port initialisieren my $tty = new Device::SerialPort($PORT) || die "can't open $PORT: $!"; $tty->baudrate(300) || die 'fail setting baudrate'; $tty->databits(7) || die 'fail setting databits'; $tty->stopbits(1) || die 'fail setting stopbits'; $tty->parity("even") || die 'fail setting parity'; $tty->write_settings || die 'fail write settings'; $tty->rts_active(1); $tty->dtr_active(1); $tty->read_char_time(500); # 0.5 seconds for each character $tty->read_const_time(3000); # 3 second per unfulfilled "read" call #$tty->debug(1); ### Anforderungstelegramm senden my $num_out = $tty->write($anforderungstelegramm); die "write failed\n" unless ($num_out); die "write inclomplete\n" unless ($num_out == length($anforderungstelegramm)); print "$num_out Bytes written\n"; ### Daten auslesen my ($num_read, $s); ### Lesebefehl - Daten werden automatisch gesendet $s = $tty->read($position); ### EMH ITZ: 539 Zeichen bis Wertende my $value = substr $s, -8; ### hier wird z.B. "001702.2" als Zählerstand ausgegeben print ($value, "\n") ; ### Ausgabe des Zählerstandes in der Konsole my $val1 = substr $value, 0, 6; ### separiert die ersten 6 Zahlen im "String 001702" my $val2 = substr $value, 7; ### spariert die letzte Zahl im String (bei 8 Stellen) #print ("val1: ",$val1,"\n"); ### Zur Kontrolle in der Konsole #print ("val2: ",$val2,"\n"); ### Zur Kontrolle in der Konsole ### Wert in DPT9 umwandeln und in Konsole ausgeben my @hexdec = encode_dpt9($value); my $hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]); print ($hexval,"\n"); ### Wert an Gruppenadresse und RRD senden system("groupwrite ip:localhost $ga $hexval"); RRDs::update("$rrd", "N: $value"); ### Log der Zählerausgabe my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time); my $timestamp = printf "%4d-%02d-%02d %02d:%02d:%02d\n",$year+1900,$mon+1,$mday,$hour,$min,$sec; open(LOG,">>$file") || die "Fehler $!"; print LOG ("\n",$year+1900,"-",$mon+1,"-",$mday," ",$hour,":",$min,":",$sec," ; ",$value); close LOG; $tty->close || die "can't close $PORT: $!"; ### SUBS 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; }
Angehängte Dateien
Einen Kommentar schreiben:
-
Zitat von JuMi2006 Beitrag anzeigenGern das ganze Plugin (wegen Timeout nicht als Wirgate-Plugin). Ich wollte euch den Thread hier bloss nicht mit meinem ganzen Code zumüllen ;-).
Obs nun ein WG-Plugin (das ist nicht die richtige Antwort auf jede Frage, manchmal gehts anders eben besser/einfacher, ist ja auch Ok und kann im OpenAutomation-SVN unter Tools seinen Platz für die Nachwelt finden..
Nun zur Frage: nimm Dir doch einfach die "sub encode_dpt9 .." aus dem wiregated.pl, die liefert die beiden Bytes von einem Float.
Oder eben den ganzen Sums (encode*, knx_write), ein
knx_write("10/1/2","001732.9",9);
tuts dann.. (statt ".." eben deine Variablen mit GA/Wert einsetzen und oben ein "use EIBConnection; - ein bis zwei Zeilen wird man aus knx_write noch rauswerfen müssen)
Makki
P.S.: Ich habe mir angewöhnt zwischen Seriellem Port und Perl immer einen socat (localhost, UDP) zu packen, das spart einem das ganze serielle gefrickel mit reconnect, restart usw..)
Einen Kommentar schreiben:
-
Gern das ganze Plugin (wegen Timeout nicht als Wirgate-Plugin). Ich wollte euch den Thread hier bloss nicht mit meinem ganzen Code zumüllen ;-).
Code:#!/usr/bin/perl # Basis von volkszähler.org # (m)ein Stromz0hler mit IR-Schnittstelle blubbert nach einem "Anforderung- # telegramm" Daten raus. Das Telegramm ist mit 300 Baud, 7 Bit, 1 Stoppbit # und gerader Parit0t zu senden. Das ist der Initialmodus von Ger0ten, # die das Protokoll IEC 62056-21 implementieren. # # Autor: Andreas Schulze # Bugfix: Eric Schanze # Datum: 20120302 # my $PORT='/dev/ttyUSB-1-4'; #Schnittstelle my $anforderungstelegramm = "/?!\r\n"; #Anforderungstelegramm my $rrd_path='var/www/rrd/'; #Pfad zum rrd my $rrd_name='Stand'; #Name des rrd my $file = '/var/tmp/log.txt'; #Logdatei use warnings; use strict; use utf8; use Device::SerialPort; use RRDs; my $tty = new Device::SerialPort($PORT) || die "can't open $PORT: $!"; $tty->baudrate(300) || die 'fail setting baudrate'; $tty->databits(7) || die 'fail setting databits'; $tty->stopbits(1) || die 'fail setting stopbits'; $tty->parity("even") || die 'fail setting parity'; $tty->write_settings || die 'fail write settings'; $tty->rts_active(1); $tty->dtr_active(1); $tty->read_char_time(500); # 0.5 seconds for each character $tty->read_const_time(3000); # 3 second per unfulfilled "read" call #$tty->debug(1); my $num_out = $tty->write($anforderungstelegramm); die "write failed\n" unless ($num_out); die "write inclomplete\n" unless ($num_out == length($anforderungstelegramm)); print "$num_out Bytes written\n"; my ($num_read, $s); $s = $tty->read(539); ### 539 Zeichen bis Wertende my $value = substr $s, -8; ### hier wird z.B. "001702.2" als Zählerstand ausgegeben print ($value, "\n") ; ### Ausgabe des Zählerstandes in der Konsole my $val1 = substr $value, 0, 5; ### separiert die ersten 6 Zahlen im "String 001702" my $val2 = substr($value,length($value)-9,1); ### spariert die letzte Zahl "2" im String mit 8 Zeichen k.A. warum "9" my @array = ("$val1","$val2"); ### Hier hab ich jetzt also die Zahl vor und die Zahl nach dem Komma - nötig ??? #print @array; ### o.k. Array angelegt ;-) ##################################### #HIER KOMME ICH JETZT INS TAL DER AHNUNGSLOSEN #Als Werte stehen hier also schon "001702.2","00172" und "2" zur Verfügung my $x= print uc(sprintf("%x", $value)), "\n"; my $wert = hexstr_to_signed32int($x); # von hex nach 32bit integer # # --- 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; } #print uc(sprintf("%x", $value)), "\n"; #print uc(sprintf("%x", $value)), "\n"; #print ($wert, "\n"); ###bringt die Vorkommalzahl als HEX my $hexval = sprintf("%x", $val1) . " " . sprintf("%x", $val2); print ($hexval, "\n"); #ENDE DES TALS ##################################### ##################################### # Log der Zählerausgabe open(LOG,">$file") || die "Fehler $!"; print LOG $s; close LOG; ### RRD schreiben und Wert senden #system("groupwrite ip:localhost 0/0/4 $val1"); $tty->close || die "can't close $PORT: $!";
Einen Kommentar schreiben:
-
Also alles auf dieser Welt tendiert z.B. dazu 0yyyy als Octal zu interpretieren, sag uns doch mal die ganze Wahrheit, also das ganze,komplette Plugin - ist unter uns - eh implizit GPL
Makki
Einen Kommentar schreiben:
-
@makki:
Mit der Mittelgruppe ist natürlich doof ;-) - senden auf den Bus klappt schonmal - nur das Format stimmt noch nicht.
RRD wird sich dann auch lösen - URRD war nen Tippfehler hier im script war es richtig.
Ich muss trotzdem nochmal ganz explizit nachfragen:
der Wert "001732.9" ist das was mir den Zählerstand angibt.
Kann der so ins RRD geschoben werden ?
Was muss ich damit machen um ihn auf den Bus zu senden ?
Zielformat ist ja DPT9 soviel hab ich verstanden. Ich bekomme es auch hin dass z.B. 1732 als dreistellige HEX (6C4) ausgegeben wird, aber das ist mehr try&error.
Also "001732.9" --> Hex --> DPT9 oder welche Reihenfolge ?
Dank und Gruß
Mirko
Einen Kommentar schreiben:
-
Zitat von JuMi2006 Beitrag anzeigenCode:URRDs::update
Code:Undefined subroutine &main::update called at /var/tmp/ehz.pl line 53
was sprich dagegen das vereinfachte update_rrd(..) zu verwenden?
2. Warum sendet groupswrite auf die 10/2/10 statt auf die 10/10/10
Zwei Möglichkeiten: den Bullshit falsch umwandeln oder ignoriren, der gewählte Weg ist "falsch" umwandeln..
Edit: Mittelgruppen gehen mal so von 0-7
Makki
Einen Kommentar schreiben:
-
Hallo
@JuMi2006
Ich bekomme ja einen String ($value) im Format 1234.5 (kWh) ausgegeben.
In die RRD-DB kannst Du diesen Wert ohne eine Umstellung schreiben.
Allerdings muss man erst eine RRD-DB erzeugen.
Um diesen Wert auf den Bus zubringen muss er umgestellt werden auf 2byte. Dafür ist "encode_dpt9($value);".
Schau mal hier bei den Tapko: Tools, da kannst Du unter DPT9(EIS5) den Wert deines Zählerstandes eingeben und bekommst dann 2byte hex zurück.
Bei einem Zählerstand von 1234.5 sind das 3788.
Gruß NetFritz
Einen Kommentar schreiben:
-
Ich hab hier nochmal ein Verständnisproblem.
Ich bekomme ja einen String ($value) im Format 1234.5 (kWh) ausgegeben.
Warum kann ich diese Zahl (oder ist es gar keine?) nicht einfach weiter verwerten?
Was muss damit getan werden.
Hier nochmal der letzte Teil des Codes:
Code:my $value = substr $s, -8; ### hier wird z.B. "1702.2" als Zählerstand ausgegeben #print $value; ### Ausgabe des Zählerstandes in der Konsole my $val1 = substr $value, 0, 5; ### separiert die ersten 6 Zahlen im String my $val2 = substr($value,length($value)-9,1); ### spariert die letzte Zahl im String mit 8 Zeichen k.A. warum "9" my @array = ("$val1","$val2"); ### Hier hab ich jetzt also die Zahl vor und die Zahl nach dem Komma - nötig ??? #print @array; ### o.k. Array angelegt ;-) my $wert = sprintf("%x", $array[0]); ### Was muss ich in was umwandeln? Ziel: RRD und Bus print $wert; ### Kontrolle in der Konsole
Falls jemand mag auch per PN - Ergebnis gibts dann natürlich hier ;-)
Einen Kommentar schreiben:
-
Hallo
groupswrite ist für 1-bit Operationen
groupwrite für alle anderen Datentypen > 1bit
Also musst Du groupwrite benutzen.
$value musst Du noch umwandeln.
Schau mal in Post #79 im Code unten bei sub encode_dpt9 .
Die Sub habe ich so augerufen
"@hexdec = "encode_dpt9($value);"
Anschließend muss das Array noch zusammengefügt werden
"$hexval = sprintf("%x", $hexdec[0]) . " " . sprintf("%x", $hexdec[1]);"
Dann $hexval mit groupwrite auf den BUS schreiben.
"system("groupwrite ip:127.0.0.1 5/0/14 $hexval"); "
Gruß NetFritz
Einen Kommentar schreiben:
-
3 kurze Fragen:
1. Warum bringt mir
Code:URRDs::update
Code:Undefined subroutine &main::update called at /var/tmp/ehz.pl line 53
3. Ich müsste $value noch irgendwie umwandeln oder?
Hier mein Code:
Code:#!/usr/bin/perl # # (m)ein Stromz0hler mit IR-Schnittstelle blubbert nach einem "Anforderung- # telegramm" Daten raus. Das Telegramm ist mit 300 Baud, 7 Bit, 1 Stoppbit # und gerader Parit0t zu senden. Das ist der Initialmodus von Ger0ten, # die das Protokoll IEC 62056-21 implementieren. # # Autor: Andreas Schulze # Bugfix: Eric Schanze # Datum: 20120302 # my $PORT='/dev/ttyUSB-1-4'; #Schnittstelle my $anforderungstelegramm = "/?!\r\n"; #Anforderungstelegramm my $rrd_path='var/www/rrd/'; #Pfad zum rrd my $rrd_name='Stand'; #Name des rrd my $file = '/var/tmp/log.txt'; #Logdatei use warnings; use strict; use utf8; use Device::SerialPort; use RRDs; my $tty = new Device::SerialPort($PORT) || die "can't open $PORT: $!"; $tty->baudrate(300) || die 'fail setting baudrate'; $tty->databits(7) || die 'fail setting databits'; $tty->stopbits(1) || die 'fail setting stopbits'; $tty->parity("even") || die 'fail setting parity'; $tty->write_settings || die 'fail write settings'; $tty->rts_active(1); $tty->dtr_active(1); $tty->read_char_time(500); # 0.5 seconds for each character $tty->read_const_time(3000); # 3 second per unfulfilled "read" call #$tty->debug(1); my $num_out = $tty->write($anforderungstelegramm); die "write failed\n" unless ($num_out); die "write inclomplete\n" unless ($num_out == length($anforderungstelegramm)); print "$num_out Bytes written\n"; my ($num_read, $s); $s = $tty->read(539); ### 539 Zeichen bis Wertende my $value = substr $s, -8; ### hier wird z.B. "1702.2" als Zählerstand ausgegeben print $value; ### Ausgabe des Zählerstandes in der Konsole system("groupswrite ip:localhost 10/10/10 test"); # Auf Bus senden #RRDs::update # Ausgabe in rrd schreiben # Log der Zählerausgabe open(LOG,">$file") || die "Fehler $!"; print LOG $s; close LOG; $tty->close || die "can't close $PORT: $!";
Danke und Gruß
Mirko
Einen Kommentar schreiben:
-
Danke !!! Damit werd ich weitermachen ... soll ja auch was fürs Hirn bei rauskommen ;-)
Einige Zähler kann man wohl nach der Initialisierung auf höheren Geschwindigkeiten weiter auslesen. Leider Fehlt mir bei EMH eine ordentlich Doku - mehr als das Datenblatt geben die nicht raus. Dort ist eine Geschwindigkeit von 4800 Baud angegeben ... wird wohl irgendwie gehen.
Ich werde dann wieder berichten und nachfragen.
Gruß Mirko
Einen Kommentar schreiben:
-
Zitat von JuMi2006 Beitrag anzeigenWie bekomme ich jetzt sauber die 1.8.0 (Zählerstand in kWh) separiert? Den Rest brauch ich eigentlich nicht wirklich. Trotz aller Bemühungen hab ich das mit Arrays immer noch nicht drauf, aber das wäre hier wohl von Vorteil.
Hier mal etwas Lektüre für den Stringvergleich mit regulären Ausdrücken: Comparing values in perl
ALTERNATIV: Wenn der Zählerstand immer an der selben Stelle im Array steht kannst du auch gleich direkt auf den Index zugreifen, dann sparst du dir die Suche nach dem Textanfang. Wie man mit Arrays umgeht siehst du hier: Arrays in Perl - Besonderheiten
Da du aber immer schrittweise liest, wird das so nicht funktionieren. Du könntest dir aber eine Zählervariable einbauen. Sprich eine Variable die du vor der Schleife mit 0 initialisierst und in der Schleife bei jedem Durchgang um eins hochzählst. Bis sie den Wert hat, an dem dein Zählerstand stehen müsste (einfach abzählen in deiner Ausgabe). Hat sie den Wert erreicht hast du deinen Zählerstand in $s, diesen Speichern und den Zähler wieder zurückstellen (auf 0). Bei der nächsten Schleifenwiederholung wird dieser wieder hochgezählt bis er wieder den Wert erreicht hat usw.
Das sollten jetzt zumindestens mal einige Stichworte für eine Google Suche gewesen sein
Einen Kommentar schreiben:
-
Zitat von JuMi2006 Beitrag anzeigenI
300 Baud
300 Baud ist halt schon seeeeeeeeeeeeeeeehr laaaaaaaaaaaaaaaaaaaaaangsam, alte Handy surfen mit der 1000fachen Geschwindigkeit, aktuelle mit ein paar tausenderstellen mehr..
Egal.. wo liegt das Problem? Für ein Perl-Plugin sind solche schnarchzapfen nicht optimal aber geht (wenige davon), cronjob: besser, den Wert halt iwo hinschreiben und dann damit machen was man anstrebt..
Makki
Einen Kommentar schreiben:
Einen Kommentar schreiben: