Benutzer-Werkzeuge

Webseiten-Werkzeuge


hardware:channels:meters:power:drs155m

Dies ist eine alte Version des Dokuments!


Hutschienenzähler DRS110M

Das Gerät ist ein Zähler mit einfacher Baubreite und Hutschinenmontage. Der Vorteil ist die integrierte RS485 Schnittstelle, die man elektronisch auslesen kann.

Das Gerät gibt es bei Amazon für 30EUR.

mechanischer Einbau

Das Gerät passt zwar auf eine Standarthutschiene, ist jedoch etwas zu hoch. Hier muss evt die Blende der Schalttafel nachgearbeitet werden.

Die Klemmen des Zähler sind allerdings sehr unschön ausgeführt. Unter 6mm^2 Anschlussleitung geht da nichts. Für einen Zähler mit 10A Dauerstrom schon recht großzügig dimensioniert.

Anschluss an den Computer: RS485 - USB Wandler

Für den Anschluss am Computer benötigt man eine RS485-USB Adapter. Ich habe hierzu von Ebay einen Adapter für 15EUR gekauft.

Bei Ebay nach „RS-485 Adapter: USB auf RS485 Power One Aurora Inverter Web Data Logger“ oder „RS-485 Interface Konverter Adapter: USB auf RS485“ suchen.

Elektrisch wird der Adapter mit dem Stromzähler A↔A , B↔B und G↔G verbunden. Ich habe keine Terminierung verwendet, bei mir ist das Kabel aber auch nur 50cm lang.

Anschluss an den Computer: Software

Für den Zähler habe ich keine richtige Software zum auslesen gefunden. Im Internet kursieren einige Scripte in PHP und Python, um den Zähler auszulesen.

Da ich ein Perl-Fan bin, habe ich das ganze unter perl zum laufen gebracht.

Es wird noch ein perl-Paket für die serielle Schnittstelle benötigt:

„apt-get install libdevice-serialport-perl“

Das script gibt die Zählerdaten auf der Console aus, eine Speicherung in die Datenbank erfolgt auch. Zuvor muss über das Webinterface der Kanal angelegt sein.

Hier dann das Perl-script

Das Script abspeichern, ausführbar machen. Das Script kann zum testen manuell aufgerufen werden. Falls alles gut läuft kann das Script im Cron zyklisch aufgerufen werden ( crontab -e ).

Der serielle Port und die uuid(die uuid bekommt man über das Webinterface von volkszähler) müssen im Script angepasst werden.

#!/usr/bin/perl -w

# teile von http://www.ip-symcon.de/forum/threads/21407-Stromz%C3%A4hler-mit-RS485/page2 entnommen
# 20130802 : ollir

use Device::SerialPort;


my $port = Device::SerialPort->new("/dev/ttyUSB0") || die $!;
$port->baudrate(9600);
$port->databits(7);
$port->parity("even");
$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(100); # 100 millisecond per unfulfilled "read" call

my $serialID = "000000000000";        # auszulesende Zähler-ID (12 Stellen), Standard: "000000000000"
my $password = "00000000"; # Standartpasswort
my $uuid="84356400-f7b8-11e2-8431-07a5d66d6531" ;

my $verbose = 2 ;

# ========================================
sub sendgetserial {
  my ($cmd) = @_;
  my $count;
  my $saw;
  my $x;

  $port->lookclear;
  $port->write( $cmd );

  ($count,$saw)=$port->read(84);   # will read 84 chars
  $x=uc(unpack('H*',$saw)); # nach hex wandeln

  $cmd =~ s/\n/\\n/mg;
  $cmd =~ s/\r/\\r/mg;

  $saw =~ s/\n/\\n/mg;
  $saw =~ s/\r/\\r/mg;

  if ( $verbose>10 ) {
    printf "+++ sendserial\n" ;
    print  " CMD: $cmd \n";  # gibt den Befehl in ASCII aus
    print  " COUNT: $count \n";  # gibt die Anzahl der empfangenen Daten aus
    print  " HEX: $x \n";  # gibt die empfangenen Daten in Hex aus
    print  " ASCII: $saw \n";  # gibt die empfangenen Daten aus
    printf "--- sendserial\n" ;
  }

  return $saw;
}
# ========================================
sub decodeVAL {
  my ($val) = @_;

  if ( $verbose>10 ) {
    printf "+++ decodeVAL\n" ;
    print " val = ( $val ) \n" ;
  }

  if($val =~ m/\((\d+)\)/) {
    if ( $verbose>10 ) {
      print " decoded val = $1\n";
      printf " --- decodeVAL\n" ;
    }
    return $1;
  }

  print " val = ( $val ) \n" ;
  die "NICHTS gefunden!\n";
  print "NICHTS gefunden!\n";
  return -8888;
}
# ========================================


## Variablen
my $cmd;
my $res;
my %vals = ();

# Abfrage der Initialisierung: hier bekommt man die $serialID raus !!
print("# INIT 1 #############\n") if ($verbose>8);
sendgetserial("/?!\r\n");


# initalisierung ueberprüfen, jetzt mit ID, wenn die ID nicht passt, kommt keine Antwort!
print("# INIT 2 #############\n") if ($verbose>8);
sendgetserial("/?" . $serialID . "!\r\n");


# ACK / Option Select Message senden ('Programming Mode')
# der programming modus muss auch bei einer einfachen Strom,Spgs-Abfrage gesetzt werden
if (1) {
  print("# PROGRAMMING MODE #############\n") if ($verbose>8);
  $cmd = chr(0x06).chr(0x30).":".chr(0x31).chr(0x0D).chr(0x0A);
  sendgetserial( $cmd);
  $cmd = chr(0x01)."P1".chr(0x02)."(".$password.")".chr(0x03).chr(0x61);
  sendgetserial( $cmd);
}

# ****************** Werte lesen
print("# SPANNUNG #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000000()".chr(0x03).chr(0x63) );
$vals { 'Spannung' } = ( decodeVAL $res  ) / 10;

print("# STROM #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000001()".chr(0x03).chr(0x62) );
$vals { 'Strom' } = ( decodeVAL $res  ) / 10;

print("# FREQUENZ #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000002()".chr(0x03).chr(0x61) );
$vals { 'Frequenz' } = ( decodeVAL $res  ) / 10;

print("# Wirkleistung #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000003()".chr(0x03).chr(0x60) );
$vals { 'PWirk' } = ( decodeVAL $res  ) * 10;

print("# Blindleistung #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000004()".chr(0x03).chr(0x67) );
$vals { 'PBlind' } = ( decodeVAL $res  ) * 10;

print("# Scheinleistung #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000005()".chr(0x03).chr(0x66) );
$vals { 'PSchein' } = ( decodeVAL $res  ) * 10;

print("# Leistungsfaktor #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000006()".chr(0x03).chr(0x65) );
$vals { 'cosphi' } = ( decodeVAL $res  ) / 1000 ;

print("# Zaehlerstand 1 #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000010()".chr(0x03).chr(0x62) );
$vals { 'Zaehler1' } = ( decodeVAL $res  ) * 1 ;
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000011()".chr(0x03).chr(0x63) );
$vals { 'Zaehler1b' } = ( decodeVAL $res  ) * 1 ;

print("# Zaehlerstand 2 #############\n") if ($verbose>8);
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000020()".chr(0x03).chr(0x61) );
$vals { 'Zaehler2' } = ( decodeVAL $res  ) * 1  ;
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000021()".chr(0x03).chr(0x60) );
$vals { 'Zaehler2b' } = ( decodeVAL $res  ) * 1  ;

print("# Temperatur #############\n") if ($verbose>8) ;
$res = sendgetserial( chr(0x01)."R1".chr(0x02)."00000032()".chr(0x03).chr(0x62) );
$vals { 'Temperatur' } = ( decodeVAL $res  )  * 1.0 ;


# ****************** LOGOUT
print("# LOGOUT #############\n") if ($verbose>8);
$cmd = chr(0x01)."B0".chr(0x03).chr(0x71) . "/?!\r\n" ;
$res = sendgetserial( $cmd);



# ****************** Werte plotten
if ($verbose>1) {
  print("# Werte plotten #############\n");
  while ( my ($key, $value) = each(%vals) ) {
    print " --> $key = $value\n";
  }
}


# ****************** Wert in die Datenbank schreiben

use LWP::UserAgent;

$val =  $vals{ "Zaehler1" } ;
print "ZAEHLERSTAND: " . $uuid . " = " . $val . "\n";

my $server_endpoint = "http://localhost/middleware.php/data/${uuid}.json?value=" . $val;
print "serverget = " .  $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(" ");

if (1) {
  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";
    }
}



Beispielausgabe

Falls das Script läuft, bekommt man folgende Ausgaben:

 --> Zaehler2b = 7450
 --> Temperatur = 22
 --> Zaehler1 = 3040
 --> Frequenz = 50
 --> Zaehler2 = 7450
 --> Zaehler1b = 3040
 --> cosphi = 0
 --> PWirk = 0
 --> PSchein = 0
 --> Spannung = 234.2
 --> PBlind = 0
 --> Strom = 0

Die Zählerangabe sind Wh.

Bugs

Ich habe mit meinem Zähler das Problem, dass der Zähler 1x am Tag für 60min nicht zählt. Die Datenkommunikation funktioniert, aber der Zähler sendet scheinbar immer die gleichen Daten. Der Fehler betrifft nur die Zählerstände, die Istwerte von Leistung, Spannung und Strom sind nicht betroffen.

Ich habe das Problem an einem zweiten Zähler verifizieren können. Das Problem tritt immer zwischen 0Uhr und 1Uhr (zählerinterne Zeit) auf.

Die Zeit kann allerdings gesetzt werden, so daß das Problem „schiebbar“ ist. Da ich den Zähler für die Solaranlage nutze, kann ich den Bug einfach auf Mitternacht schieben.

Todos

  • Werte in die Datenbank schreiben
  • prüfen, ob das script auch bei mehreren Zähler an einem RS485 läuft
  • die ID der Zähler setzen
  • die Passwörter der Zähler setzen
hardware/channels/meters/power/drs155m.1377340250.txt.gz · Zuletzt geändert: 2013/08/24 12:30 von ollir