Conrad hat einen preisgünstigen Drehstromzähler mit S0-Schnittstelle und Modbus in RS-485 Variante und Infrarot. Leider gibt es dazu kaum Doku.
Nach dem Kauf des Komplettsystems und etwas Schnittstellenauswertung und probieren gibt's dazu hier ein paar weitere Infos.
Bei weiteren Infos oder Fragen am Besten hier eintragen.
Der Zähler hat eine RS-485 Schnittstelle zum Abfragen. Diese arbeitet in der Betriebsart 8e2. Bisher ist nur die Geschwindigkeit mit 1200 baud getestet worden. Laut Doku sollte es auch schneller gehen.
Der Modbus wird binär nach RTU betrieben. Siehe dazu auch http://de.wikipedia.org/wiki/Modbus und insbesondere http://www.simplymodbus.ca/. Grundätzliche Idee: Es gibt einen Master und mehrere Slaves. Der Master schickt Anfragen an die Slaves die darauf antworten.
Der VSM-Zähler erkennt (mindestens und soweit bekannt) Anfragen nach dem Schema
ID | Funktion | Register | Länge | CRC | ||
---|---|---|---|---|---|---|
Beschreibung | Für VMS-103: 1, 1 Byte | Für VSM-103: 4, 1 Byte | 2 Byte, je nach gewünschtem Wert | 2 Byte, bei VSM-103 immer 2 | CRC, 2 Byte | |
Beispiel (hex) | 01 | 04 | 00 96 | 00 02 | 91 e7 | Momentanen Wirk-Gesamtleistung? |
Auf erkannte Anfragen antwortet der Zähler dann mit einem Datentelegramm mit meist 8 Byte (Achtung: das folgende Beispiel ist nicht konsistent: es enthält eine 9 Byte Antwortnachricht, passt nicht zum 8 Byte Format):
ID | Funktion | Daten-Laenge | Daten | CRC | ||
---|---|---|---|---|---|---|
Beschreibung | Für VMS-103: 1, 1 Byte | Für VSM-103: 4, 1 Byte | Anzahl der Bytes der Antwort, 1 Byte | Daten | CRC | |
Beispiel (hex) | 01 | 04 | 04 | 3b a3 d7 0a | d9 75 | Momentanen Wirk-Gesamtleistung: 0,05 kWatt |
Die Antworten liegen (soweit bisher bekannt) in den 4 Byte als 32Bit Gleitkommazahl vor: http://de.wikipedia.org/wiki/IEEE_754. Wer damit bisher nicht zu tun hatte, hier gibt's eine Excel-Vorlage zum berechnen: http://www.simplymodbus.ca/FAQ.htm#Types
Auch hier http://www.simplymodbus.ca/FAQ.htm#CRC gibt's eine Excel-Vorlage um die 2-Byte CRC zu berechnen. Der VSM-103 beantwortet nur Anfragen mit korrekter CRC.
Register | hex | Art | Beschreibung | Einheit | Stellen(*) | Bemerkung |
---|---|---|---|---|---|---|
16 | 0010 | U1 | Spannung zwischen N und L1 | [V] | ||
18 | 0012 | U2 | Spannung zwischen N und L2 | [V] | ||
20 | 0014 | U3 | Spannung zwischen N und L3 | [V] | ||
78 | 004e | F | Frequenz | [Hz] | 2 | |
80 | 0050 | I1 | Strom auf L1 | [A] | ||
82 | 0050 | I2 | Strom auf L2 | [A] | ||
84 | 0052 | I3 | Strom auf L3 | [A] | ||
86 | 0054 | IN | Strom auf N | [A] | ?? IN und I geben gleiche Werte?! | |
88 | 0058 | I | Strom gesamt | [A] | ||
144 | 0090 | P1 | Wirkleistung auf L1 | [kW] | 3 | –>1 Watt Auflösung |
146 | 0092 | P2 | Wirkleistung auf L2 | [kW] | 3 | |
148 | 0094 | P3 | Wirkleistung auf L3 | [kW] | 3 | |
150 | 0096 | P | Wirkleistung gesamt | [kW] | 3 | |
208 | 00d0 | S1 | Scheinleistung L1 | [kvar] | 3 | |
210 | 00d2 | S2 | Scheinleistung L2 | [kvar] | 3 | |
212 | 00d4 | S3 | Scheinleistung L3 | [kvar] | 3 | ?? Bei mir immer Null?! |
214 | 00d6 | S | Scheinleistung ges | [kvar] | 3 | |
272 | 0110 | Q1 | Blindleistung L1 | [kvar] | 3 | |
274 | 0112 | Q2 | Blindleistung L2 | [kvar] | 3 | |
276 | 0114 | Q3 | Blindleistung L3 | [kvar] | 3 | |
278 | 0116 | Q | Blindleistung ges | [kvar] | 3 | |
336 | 0150 | LF1 | Leistungsfaktor L1 | |||
338 | 0150 | LF2 | Leistungsfaktor L2 | |||
340 | 0150 | LF3 | Leistungsfaktor L3 | |||
342 | 0150 | LF | Leistungsfaktor ges | |||
352 | 0160 | Z1 | Zaehlerstand Wirkenergiebezug | [kWh] | 2 | –>0,01 kWh Auflösung |
354 | 0162 | Z2 | Zaehlerstand Blindenergiebezug? | [kWh] | 2 | nur Vermutung, nicht bestätigt |
358 | 0160 | Z3 | Zaehlerstand Wirkenergieabgabe? | [kWh] | 2 | nur Vermutung, nicht bestätigt |
360 | 0168 | Z4 | Zaehlerstand Blindenergieeinspeisung? | [kWh] | 2 | nur Vermutung, nicht bestätigt |
1318 | 0526 | ?? | VSM Antwortet mit: 0x01040456341256275c | |||
1560 | 0618 | ?? | Zaehlerstand ? | |||
65298 | ff12 | ?? | ||||
65314 | ff22 | ?? |
Auch bei Einträgen ohne Fragezeichen ist die Beschreibung nicht absolut sicher, solange niemand das Bestätigt bitte die erhaltenen Werte auf Sinnhaftigkeit prüfen!
(*) Hier nur: Aussage über die Nachkommastellen, nicht über die Messgenauigkeit
Der VSM-103 verfügt über zwei S0-Schnittstellen für Wirk- und Blindenergie mit einer Konstante von 400 Impulsen pro kWh. Ungetestet.
Per Infrarot soll ebenfalls eine Modbus-RTU Kommunikation mit 1200 baud möglich sein. Ungetestet.
Bin kein guter Softwerker, aber es funktioniert Verbesserungen willkommen.
#!/usr/bin/perl # Nur bischen Zeit fuer die Logdatei aufbereiten... $unix_time = time; ($jahr, $monat, $tag, $stunde, $minute, $sekunde) = (localtime)[5,4,3,2,1,0]; $monat=$monat+1; $jahr=$jahr+1900; if ($tag<10) {$tag='0'.$tag;} if ($monat<10) {$monat='0'.$monat;} if ($stunde<10) {$stunde='0'.$stunde;} if ($minute<10) {$minute='0'.$minute;} if ($sekunde<10) {$sekunde='0'.$sekunde;} # Anfrage an den Terminalserver (http://wut.de/e-58631-ww-dade-000.php ) # Sollte auch ueber normale Serielle gehen. Dann mit Adapter RS-232<-->RS-485 use IO::Socket; $socket = IO::Socket::INET->new(PeerAddr=> "192.168.1.23", # Terminalserver PeerPort=> "8000", Proto => "tcp") or die "Kaputt!"; # Vordefinierte Register, CRC ist da schon berechnet :-) Hier nur zwei, sonst wird's arg unuebersichtlich. # Momentanleistung 150 $frage[0]=pack('H*',"01040096000291e7"); # Zaehlerstand > 352 $frage[1]=pack('H*',"01040160000fb1ec"); # Wie erhaelt man nochmal die Laenge eines Arrays? ;-) $fragen=2; # Nun fuer jeden Angfragestring durchlaufen for ($anfrage=0; $anfrage < $fragen; $anfrage++) { # Den Anfragestring an den Anschluss schicken. print $socket $frage[$anfrage]; # Einlesen von 8 Byte # Es werden stumpf 8 Byte erwartet, nix mit Timout oder so... $i=-1; while ($i < 8 ){ sysread($socket, my ($byte), 1); $i++; $antwort[$i]=$byte; } $antwortcount=$i; # In der Subroutine den Wert umrechnen. # Es werden stumpf die Datenbits genommen, nix CRC-Pruefung oder so... $wert[$anfrage]=parse32b($antwort[3],$antwort[4],$antwort[5],$antwort[6]); } close($socket); # Jetzt werden die ermittelten Werte in einer Zeile die Logdatei angehaengt, mit ';' getrennt open (LOG,">>/pfad/datei") or die "Logdatei kann nicht geschrieben werden"; print LOG $jahr.$monat.$tag."T".$stunde.$minute.$sekunde.';'.$unix_time.";"; for ($anfrage=0; $anfrage < $fragen; $anfrage++) { print LOG $wert[$anfrage].";" } print LOG "\n"; close(LOG); sub parse32b # 32bit nach Dezimal wandeln, http://de.wikipedia.org/wiki/IEEE_754 { ($byte0, $byte1, $byte2, $byte3) = @_; # So klappts nicht. Vielleicht irgend was falsch herum? #print "Bytes: ". unpack('H*',$byte0) ." ". unpack('H*',$byte1) ." ". unpack('H*',$byte2) ." ". unpack('H*',$byte3). "\n"; #$ra = unpack('f*',$byte0. $byte1. $byte2. $byte3); #print $ra."\n"; ## So klappen's, wenn auch nicht so elegant $bin=unpack('B*', $byte0.$byte1.$byte2.$byte3 ); $sign=substr($bin,0,1); if ($sign==1){$sign=-1;} if ($sign==0){$sign=+1;} $exponent=substr($bin,1,8); $exponent=oct("0b".$exponent); $exponent=$exponent-127; $mantisse=substr($bin,9); $mantisse=oct("0b".$mantisse); $mantisse=$mantisse/8388608; $mantisse=1+$mantisse; $wert= $sign * $mantisse * ( 2 ** $exponent ) ; return($wert); }