Benutzer-Werkzeuge

Webseiten-Werkzeuge


howto:emh_pv-anlage

Volkszaehler auf einem PC mit Ubuntu installieren (PV-Anlage mit zwei EMH eHZ-Zählern)

Beispiel um eine PV-Anlage mit zwei EMH eHZ-Zählern auszulesen.

Die hier beschriebene PV-Anlage wurde 2011 mit Volleinspeisung errichtet und im Dezember 2012 auf Direktverbrauch umgestellt. Sie hat eine Leistung von 7,62 kWp, besteht aus 32 Sunpower SPR-238 Solarmodulen und einem Sunpower SPR-8001-F2 (baugleich Fronius IG Plus 100-V2) Wechselrichter.

Vor der Umstellung auf Direktverbrauch wurden der Bezug durch einen mechanischen Ferraris-Drehstromzähler und die Lieferung durch einen EMH eHZ gemessen.

Nach der Umstellung wurde der Ferraris-Drehstromzähler vom VNB (Verteilungs-Netz-Betreiber) gegen einen Zweirichtungszähler EDL21 eHZ für Bezug und Einspeisung ausgetauscht. Der EMH eHZ verblieb als Erzeugungszähler. Der Zweirichtungszähler zeigt im Wechsel für jeweils 15 Sekunden den Wert für Bezug +A und Lieferung -A an.

GeneratorfeldWechselrichterZählerschrankZweirichtungszähler Anzeige BezugZweirichtungszähler Anzeige LieferungErzeugungszählerAnlagenschema

Aufbau des Loggers

Das Loggen der Daten erfolgt auf einem Laptop Dell Latitude D800 (Pentium M). Auf dem Laptop wurde Ubuntu 12.10 mit MySql, PHP und Lighttpd installiert. Statt Lightpd kann man auch Apache nehmen. Ich habe Lighttpd gewählt, weil das Loggen später einmal meine D-Link DNS-323 NAS übernehmen soll. Für die gibt es die Möglichkeit ein Linux auf ihr zu installieren und in dem zur Zeit installierten fun_plug 0.5 ist als Webserver eben der Lighttpd enthalten. Da wollte ich schon mal Erfahrungen sammeln. Die beiden Zähler werden mit je einem USB-IR-Lesekopf am Laptop angeschlossen.

Zweirichtungszähler mit LesekopfErzeugungszähler mit Lesekopf Laptop

Installation der Volkszähler Software

Installation wie im Installationsleitfaden beschrieben.

Installation von libsml und vzlogger

Dieser Teil ist obsolete. Deshalb gelöscht. Die Installation bitte nach diesen Anleitungen vornehmen:
vzlogger und middleware
Oder gleich das fertige Image für die Raspi-Varianten nehmen: Image-Quelle

USB-IR-Leseköpfe konfigurieren

Eigentlich ist an den USB-IR-Leseköpfen nichts zu konfigurieren. Wie in USB-IRLesekopf Linux Support beschrieben, kann es passieren, dass die Leseköpfe nicht immer den gleichen Devicenamen bekommen. Aber das udev System bietet da Abhilfe an. Wir sagen dem udev System, dass es anhand der Seriennummer des Lesekopfes immer einen sym. Link zum richtigen Device anlegen soll. Wir benutzen dann in der Konfiguration immer die sym. Links.

Dazu muss man die Seriennummer ermitteln.

# udevadm info --query=all --name=/dev/ttyUSB0

Ergibt dann folgende etwas gekürzte Ausgabe.

P: /devices/pci0000:00/0000:00:1d.1/usb3/3-1/3-1:1.0/ttyUSB0/tty/ttyUSB0
N: ttyUSB0
S: serial/by-id/usb-Silicon_Labs_CP2104_USB_to_UART_Bridge_Controller_0061E011-if00-port0
...
E: ID_SERIAL_SHORT=0061E011
...
E: SUBSYSTEM=tty
...

Davon interessiert uns ID_SERIAL_SHORT=0061E011. Das ist die Seriennummer des Lesekopfes. Das wiederholt man für den zweiten Lesekopf, der unter „/dev/ttyUSB1“ zu finden sein wird.

Man erstellt jetzt eine Datei “/etc/udev/rules.d/99-usb-ir-lesekopf.rules“ mit folgendem Inhalt.

SUBSYSTEM=="tty", ENV{ID_SERIAL_SHORT}=="0061E011", SYMLINK+="usb-ir-lesekopf0"
SUBSYSTEM=="tty", ENV{ID_SERIAL_SHORT}=="0061DF28", SYMLINK+="usb-ir-lesekopf1"

Natürlich statt „0061E011“ und „0061DF28“ die eigenen Seriennummern verwenden.

Ein anschließendes

# udevadm trigger

bringt das udev System dazu die neue Regel anzuwenden und die beiden sym. Links anzulegen. Die beiden Leseköpfe sind ab sofort immer unter „/dev/usb-ir-lesekopf0“ und „/dev/usb-ir-lesekopf1“ ansprechbar.

# ls -la /dev/usb*
lrwxrwxrwx 1 root root 7 Jan 13 22:19 /dev/usb-ir-lesekopf0 -> ttyUSB0
lrwxrwxrwx 1 root root 7 Jan 13 22:19 /dev/usb-ir-lesekopf1 -> ttyUSB1

Anschliessend kann man dann gleich mal testen, ob die neuen Device sym. Links auch funktioieren. Testmoeglichkeiten unter Linux

Kanäle in der Middleware erstellen

Nun erstellen wir die Kanäle in der Middleware. Dazu in einem Browser die IP des Raspi aufrufen. Wir brauchen insgesamt sieben Stück. Vier mit Leistungswerten und drei Zählerständen. Bei allen Kanälen: Style „steps“ einstellen, sowie öffentlich, aktiv und Cookie aktivieren. Bei den Kanälen 1, 3 und 5 kann man unter Kosten noch die Vergütung bzw. den Strompreis angeben. Wird z.B. der Direktverbrauch mit 0,1236 €/kWh vergütet, trägt man 0.0001236 unter Kosten ein. Bekommt man 0,2874 €/kWh für Einspeisung, dann 0.0002874 bei Kanal 5 eintragen und kostet die kWh vom Energieversorger 0,2575 €, dann 0.0002575 bei Kanal 3 eingeben.

  • Kanal 1: Direktverbrauch, Typ El. Energie (Leistungswerte)
  • Kanal 2: Gesamtverbrauch, Typ El. Energie (Leistungswerte)
  • Kanal 3: Haus 1.8.0 (Bezug +A), Typ El. Energie (Zählerstände), Auflösung 1000
  • Kanal 4: Haus 16.7.0 (Leistung), Typ El. Energie (Leistungswerte)
  • Kanal 5: Haus 2.8.0 (Lieferung -A), Typ El. Energie (Zählerstände), Auflösung 1000
  • Kanal 6: PV 2.7.0 (Leistung), Typ StomEl. Energie (Leistungswerte)sensor
  • Kanal 7: PV 2.8.1 (Erzeugung -A), Typ El. Energie (Zählerstände), Auflösung 1000

Kanal-StromsensorKanal-Stromzähler

Beim Erstellen der Kanäle werden automatisch auch die UUIDs der Kanäle in der MySQL Datenbank angelegt. Diese UUIDs brauchen wir später noch. Es aber nicht nötig die jetzt zu notieren, da wir da jederzeit leicht ran kommen. Neben den erstellten Kanälen finden wir dieses Zeichen , mit dem wir die UUID später abrufen können.

Die Namen der Kanäle können selbstverständlich frei gewählt werden. Ich habe mich jedoch an den OBIS-Kennzahlen, die meine Zähler ausgeben orientiert. Wie man die ermittelt, dazu komme ich noch.

vzlogger konfigurieren

Kommen wir nun zum vzlogger. vzlogger ist der Teil, der die Zähler ausliest und die Daten per Middleware in die MySQL Datenbank speichert. Um eine passende vzlogger.conf zu erstellen, wollen wir jetzt erstmal wissen, was unsere Zähler den so von sich geben. Dazu erstellen wir uns nun eine minimale /etc/vzlogger.conf die nur das Notwendigste enthält.

/**
 * vzlogger configuration
 * 
 * use proper encoded JSON with javascript comments
 *
 * take a look at the wiki for detailed information:
 * http://wiki.volkszaehler.org/software/controller/vzlogger#configuration
 */

{
"retry" : 0,                   /* how long to sleep between failed requests, in seconds */
"daemon": false,                /* run periodically */
"verbosity" : 15,               /* between 0 and 15 */
"log" : "/tmp/vzlogger.log",/* path to logfile, optional */

"local" : {
        "enabled" : false,      /* should we start the local HTTPd for serving live readings? */
        "port" : 8080,            /* the TCP port for the local HTTPd */
        "index" : true,         /* should we provide a index listing of available channels? */
        "timeout" : 30,         /* timeout for long polling comet requests, 0 disables comet, in seconds */
        "buffer" : 600          /* how long to buffer readings for the local interface, in seconds */
},

"meters" : [{
        "enabled" : true,       /* disabled meters will be ignored */
        "protocol" : "sml",     /* use 'vzlogger -h' for list of available protocols */
        "device" : "/dev/usb-ir-lesekopf0",
        },{
        "enabled" : true,       /* disabled meters will be ignored */
        "protocol" : "sml",     /* use 'vzlogger -h' for list of available protocols */
        "device" : "/dev/usb-ir-lesekopf1",
        }
]}

Wenn wir jetzt

sudo systemctl start vzlogger

aufrufen, dann sollte eine Ausgabe in folgender Art auf dem Bildschirm erscheinen.

[Jan 15 22:30:39][]     ===> Start meters.
[Jan 15 22:30:39][mtr0] Meter connection established
[Jan 15 22:30:39][mtr0] Meter thread started
[Jan 15 22:30:39][mtr0] meter is opened. Start channels.
[Jan 15 22:30:39][mtr0] Number of readers: 32
[Jan 15 22:30:39][mtr0] Config.daemon: 0
[Jan 15 22:30:39][mtr0] Config.local: 0
[Jan 15 22:30:39][mtr1] Meter connection established
[Jan 15 22:30:39][mtr1] Meter thread started
[Jan 15 22:30:39][mtr1] meter is opened. Start channels.
[Jan 15 22:30:39][]     Startup done.
[Jan 15 22:30:39][mtr1] Number of readers: 32
[Jan 15 22:30:39][mtr1] Config.daemon: 0
[Jan 15 22:30:39][mtr1] Config.local: 0
[Jan 15 22:30:42][mtr0] Got 11 new readings from meter:
[Jan 15 22:30:42][mtr0] Reading: id=129-129:199.130.3*255/ObisItentifier:129-129:199.130.3*255 value=0.00 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:0.0.9*255/ObisItentifier:1-0:0.0.9*255 value=0.00 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:1.8.0*255/ObisItentifier:1-0:1.8.0*255 value=756082.40 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:2.8.0*255/ObisItentifier:1-0:2.8.0*255 value=26925.90 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:1.8.1*255/ObisItentifier:1-0:1.8.1*255 value=756082.40 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:2.8.1*255/ObisItentifier:1-0:2.8.1*255 value=26925.90 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:1.8.2*255/ObisItentifier:1-0:1.8.2*255 value=0.00 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:2.8.2*255/ObisItentifier:1-0:2.8.2*255 value=0.00 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=1-0:16.7.0*255/ObisItentifier:1-0:16.7.0*255 value=561.30 ts=1358285442.060
[Jan 15 22:30:42][mtr0] Reading: id=129-129:199.130.5*255/ObisItentifier:129-129:199.130.5*255 value=0.00 ts=2210964.000
[Jan 15 22:30:42][mtr0] Reading: id=0-0:0.0.0*0/ObisItentifier:0-0:0.0.0*0 value=0.00 ts=0.000
[Jan 15 22:30:42][mtr0] Updating interval to 3
[Jan 15 22:30:42][mtr1] Got 6 new readings from meter:
[Jan 15 22:30:42][mtr1] Reading: id=129-129:199.130.3*255/ObisItentifier:129-129:199.130.3*255 value=0.00 ts=1358285442.080
[Jan 15 22:30:42][mtr1] Reading: id=1-0:0.0.9*255/ObisItentifier:1-0:0.0.9*255 value=0.00 ts=1358285442.080
[Jan 15 22:30:42][mtr1] Reading: id=1-0:2.8.1*255/ObisItentifier:1-0:2.8.1*255 value=12018020.10 ts=1358285442.080
[Jan 15 22:30:42][mtr1] Reading: id=1-0:1.7.0*255/ObisItentifier:1-0:1.7.0*255 value=0.00 ts=1358285442.080
[Jan 15 22:30:42][mtr1] Reading: id=1-0:2.7.0*255/ObisItentifier:1-0:2.7.0*255 value=0.00 ts=1358285442.080
[Jan 15 22:30:42][mtr1] Reading: id=0-0:0.0.0*0/ObisItentifier:0-0:0.0.0*0 value=0.00 ts=0.000
[Jan 15 22:30:42][mtr1] Updating interval to 3

Nun sehen wir alle OBIS-Kennzahlen die unsere Zähler ausgeben. mtr0 ist der Zähler an /dev/usb-ir-lesekopf0 (im Beispiel der Zweirichtungszähler) und mtr1 der Zähler an /dev/usb-ir-lesekopf1 (Erzeugungszähler). Nun ist auch ersichtlich, warum ich die Kanäle so benannt habe, wie ich es tat.

Nun kann man die korrekte /etc/vzlogger.conf erstellen. Für die Beispielanlage brauchte ich

Vom Zweirichtungszähler

  • 1.8.0 = Wirkarbeit Bezug +A
  • 2.8.0 = Wirkarbeit Lieferung -A
  • 16.7.0 = Wirkleistung

Vom Erzeugungszähler

  • 2.7.0 = Wirkleistung
  • 2.8.1 = Wirkarbeit Lieferung -A

Nun, das sind fünf Kanäle, die aus den Zählern in der Datenbank landen, warum aber wurden sieben Kanäle angelegt? Dazu kommen wir später. Geduld!

Die restlichen OBIS-Kennzahlen, die die Zähler ausgeben werden nicht benötigt

  • 1.8.1 = Wirkarbeit Bezug Tarif 1 (da nur Tarif 1, ist 1.8.0 = 1.8.1)
  • 1.8.2 = Wirkarbeit Bezug Tarif 2 (nicht vorhanden)
  • 2.8.1 = Wirkarbeit Lieferung Tarif 1 (da nur in Tarif 1, ist auch hier 2.8.0 = 2.8.1)
  • 2.8.2 = Wirkarbeit Lieferung Tarif 2 (nicht vorhanden)
  • 1.7.0 = Wirkleistung Bezug ?

Jetzt ist auch der Moment, wo wir die im Abschnitt "Kanäle in der Middleware erstellen" erstellten UUIDs benötigen. Die UUIDs wie oben beschrieben auslesen und an die korrekte Stelle einfügen.

UUID ermitteln

/**
* vzlogger configuration
*
* use proper encoded JSON with javascript comments
*
* take a look at the wiki for detailed information:
* http://wiki.volkszaehler.org/software/controller/vzlogger#configuration
*/

{
"retry" : 0, /* how long to sleep between failed requests, in seconds */
"daemon": true, /* run periodically */
"verbosity" : 15, /* between 0 and 15 */
"log" : "/tmp/vzlogger.log", /* path to logfile, optional */

"local" : {
"enabled" : false, /* should we start the local HTTPd for serving live readings? */
"port" : 80, /* the TCP port for the local HTTPd */
"index" : true, /* should we provide a index listing of available channels if no UUID was requested? */
"timeout" : 30, /* timeout for long polling comet requests, 0 disables comet, in seconds */
"buffer" : 600 /* how long to buffer readings for the local interface, in seconds */
},

"meters" : [{
         "enabled" : true, /* disabled meters will be ignored */
         "protocol" : "sml", /* see 'vzlogger -h' for list of available prot$ */
         "device" : "/dev/usb-ir-lesekopf0",
         "channels": [{
         "uuid" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
         "middleware" : "http://localhost/middleware.php",
         "identifier" : "1-0:16.7.0", /* Leistung */
         }, {
         "uuid" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
         "middleware" : "http://localhost/middleware.php",
         "identifier" : "1-0:1.8.0", /* Wirkarbeit Bezug +A */
         }, {
         "uuid" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
         "middleware" : "http://localhost/middleware.php",
         "identifier" : "1-0:2.8.0", /* Wirkarbeit Lieferung -A */
         }]
         }, {
         "enabled" : true,
         "protocol" : "sml",
         "device" : "/dev/usb-ir-lesekopf1",
         "channels" :[{
         "uuid" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
         "middleware" : "http://localhost/middleware.php",
         "identifier" : "1-0:2.7.0", /* Leistung Erzeugung */
         }, {
         "uuid" : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
         "middleware" : "http://localhost/middleware.php",
         "identifier" : "1-0:2.8.1", /* Wirkarbeit Erzeugung -A */
         }]
}
]}

Speichern als „/etc/vzlogger.conf“.Testen dann mit

sudo systemctl start vzlogger

Nach erfolgreichem Test noch „verbosity“ : 15, in „verbosity“ : 0, ändern.

Script für Gesamt- und Direktverbrauch

Nun ist neben dem Bezug und der Lieferung auch der Gesamt- und Direktverbrauch von Interesse. Diese Werte können jedoch nicht aus den Zählern ausgelesen werde. Sie können nur durch Berechnung ermittelt werden.

  • Gesamtverbrauch = Bezug + Erzeugung - Lieferung
  • Direktverbrauch = Erzeugung - Lieferung

Da alle für die Berechnung notwendigen Werte vorliegen erstellt man ein Script (gefunden im Photovoltaikforum und etwas erweitert) und lässt es kontinuierlich durch Cron ausführen.

Damit das Script funktioniert, muss zuerst Curl installiert werden (fehlt im aktuellen Raspberry Image).

sudo apt-get install php5-curl

Folgendes Script z.B. als /var/www/volkszaehler.org/htdocs/direktverbrauch.php speichern und die richtigen UUIDs eintragen. (Script geändert, es werden nun keine Nullen mehr bei Null Direktverbrauch in die Datenbank geschrieben)

<?php
    $urlBase='http://localhost/middleware.php/data/';
    $uuIds=array( 'Bezug' => 'a2fc7c10-5c06-11e2-a9fd-07ec3529dbce',
                  'Lieferung' => '295f8cd0-5c07-11e2-833b-39e13950d0c2',
                  'Erzeugung' => '83cd0400-5c1a-11e2-a8b1-41ba0e4e3b55',
                );
    
    $uuIdTarget=array('Gesamtverbrauch' => '72c08b30-5da7-11e2-ae92-c3c944e97303',
                      'Direktverbrauch' => '75bc5f20-5dab-11e2-97e3-035e5f4fa046'
                     );

    $urlEnd='.json?from=30%20seconds%20ago';

function curl_file_get_contents($URL)
    {
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_URL, $URL);
    $contents = curl_exec($c);
    curl_close($c);

    if ($contents) return $contents;
    else return FALSE;
    } // function curl_get_file_contents

function getTimestamp() {
    $seconds = microtime(true); // false = int, true = float
    return round( ($seconds * 1000) );
    }

for ($i=1; $i<5 ; $i++) {
    $minTimestamp = getTimestamp();
    $maxTimestamp = $minTimestamp;
    foreach($uuIds as $index=>$value) {
      $url=$urlBase . $value . $urlEnd;
      $content = curl_file_get_contents($url);
      $content=json_decode($content);
      if (!empty($content->data->tuples)) {

         $lastTuple = end($content->data->tuples);
         $minTimestamp = min($minTimestamp,$lastTuple[0]);
         $maxTimestamp = max($maxTimestamp,$lastTuple[0]);
         print_r($lastTuple);
         $lastValue = $lastTuple[1];
      } else {
        $lastValue=0;
    } // if
    echo "$value / $index: $lastValue\n<br>";

    $values[$index]=$lastValue;
    } // foreach

    $diffGV= $values['Bezug'] + $values['Erzeugung'] - $values['Lieferung'];
    echo "Gesamtverbrauch = Bezug + Erzeugung - Lieferung: $diffGV \n<br>";
    $timestamp = round($minTimestamp + ( ($maxTimestamp - $minTimestamp) / 2 ));
    $linkGV=$urlBase . $uuIdTarget['Gesamtverbrauch'] . '.json?operation=add&value=' . $diffGV . '&ts=' . $timestamp;
    $dummy=curl_file_get_contents($linkGV);
    echo "$linkGV \n<br>";
    
    $diffDV= $values['Erzeugung'] - $values['Lieferung'];
    echo "Direktverbrauch = Erzeugung - Lieferung : $diffDV \n<br>";
    if ($diffDV>0) {
        $linkDV=$urlBase . $uuIdTarget['Direktverbrauch'] . '.json?operation=add&value=' . $diffDV . '&ts=' . $timestamp;
        $dummy=curl_file_get_contents($linkDV);
        echo "$linkDV \n<br>";
    }
    sleep(15);
} // for
?>

Zum testen mit

# php /var/www/volkszaehler.org/htdocs/direktverbrauch.php

aufrufen. Die Ausgabe sollte dann so aussehen. Jeweils 4 mal mit 15 s Pause.

xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / Bezug: 653.358
<br>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / Lieferung: 0
<br>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / Erzeugung: 0
<br>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / Gesamtverbrauch: 0
<br>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx / Direktverbrauch: 0
<br>Gesamtverbrauch = Bezug + Erzeugung - Lieferung: 653.358 
<br>Direktverbrauch = Erzeugung - Lieferung: 0 

Fehlt nur noch der Crontab Eintrag. Unbedingt als letzte Zeile eine Leerzeile machen. Sonst funktioniert Cron nicht.

# crontab -e

MAILTO=""
* * * * * /usr/bin/php /var/www/volkszaehler.org/htdocs/direktverbrauch.php > /dev/null
# Hinter diesem Text noch eine Leerzeile einfuegen, sonst funktioniert cron nicht!

Ergebnis der Bemühungen

Wurde alles korrekt eingerichtet, dann sollte sich unter http://localhost/frontend/ folgendes Bild bieten. Man beachte die enorme Erzeugung und den ebenso enormen Direktverbrauch. :-) Das Modulfeld war an dem Tag zugeschneit. :-(

Ansicht

Danke für die Aufmerksamkeit.

Hier noch ein kleines Tuning an der Darstellung. Gefüllte Flächen im Diagramm

Ansicht gefüllte Flächen

howto/emh_pv-anlage.txt · Zuletzt geändert: 2017/01/03 18:26 von udo1