Benutzer-Werkzeuge

Webseiten-Werkzeuge


hardware:channels:meters:power:eastron_drs155m

Eastron DRS110M

eastron_drs115m.jpg

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.
Elektrisch wird der Adapter mit dem Stromzähler A↔A , B↔B und G↔G verbunden. Bei kurzer Kabellänge (50cm) kann auf die Terminierung verzichtet werden.

Adressen:

Oder auch Modbusregister.
Einige davon waren in der offiziellen Doku nicht enthalten, es kann daher sein das sie nicht von allen Zählermodellen bereitgestellt werden.

Name Adresse Byte Faktor Einheit
Spannung 00000000 2 0.1 V
Strom 00000001 2 0.1 A
Frequenz 00000002 2 0.1 Hz
Wirkeistung 00000003 2 10 W
Blindleistung 00000004 2 10 VAr
Scheinleistung 00000005 2 10 VA
Zaehler1 00000010 4 1 Wh
Zaehler1a 00000011 4 1 Wh
Zaehler2 00000020 4 1 Wh
Zaehler2a 00000021 4 1 Wh
Zeit 00000031 1 Format?
Temperatur 00000032 2 1 °C
Serielle Schnittstelle 00000034 6
Baudrate 00000035 2
Meter ID 00000036 6
Passwort 00000037 4
Reset Zählerstände 00000040 0

Registerwerte für die Baudrate:

Wert Baud
0001 1200
0002 2400
0003 4800
0004 9600

Anschluss an den Computer: Software

Im Internet kursieren einige Scripte in PHP und Python, um den Zähler auszulesen.

Perl-Script

Es werden Pakete für die serielle Schnittstelle benötigt:

sudo apt-get install libdevice-serialport-perl
sudo apt-get install libwww-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.

Der serielle Port und die UUID (diese 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";
    }
}

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).

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

Der Zähler hat das Problem, dass er 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.

Das Problem konnte 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. Wer den Zähler für die Solaranlage nutzt, kann 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/eastron_drs155m.txt · Zuletzt geändert: 2018/03/25 11:11 von jau