Benutzer-Werkzeuge

Webseiten-Werkzeuge


hardware:channels:meters:power:edl-ehz:itron_ace3000_type_260

Itron ACE3000 Type 260

Hardware

Der ACE3000 hat eine Infrarot-Schnittstelle nach DIN EN 62056-21 Mode C-a, die für die Auswertung mit einen IR-Schreib-Lesekopf ausgelesen werden kann.

Der Stromzähler gibt von sich aus gar keine oder nur S0-Impulse über Die Frontschnitttstelle aus. Diese Impulse sind bei einem Zweirichtungszähler nicht sinnvoll auszuwerten, da keine Trennung zwischen Bezug und Einspeisung möglich ist.

Für die Kommunikation mittels d0-Protokoll muss zuerst eine Initialisierungs-Sequenz „/?!“ mit 300bd, 7E1 und „LF+CR“ geschickt werden, um ihn zum Antworten zu bewegen. Die Baudrate kann bei dem Zähler nicht geändert werden und bleibt bei 300bd.

Zusätzlich hat er einen rückseitigen S0-Ausgang, dieser ist allerdings normalerweise verplombt und nur gegen Gebühr zugänglich.

Auslesen des Zählers mittels vzlogger

Das Auslesen des Zählers kann auf zwei Arten erfolgen:

  1. durch Auslesen der d0-Daten.
  2. durch Erfassen der S0-Impulse.

Beide Arten können mit dem IR-Schreib-Lesekopf erfasst und mit vzlogger ausgewertet werden. Aber immer nur wahlweise.

vzlogger.conf für d0-Daten

Um die d0-Daten des ACE3000 an der IR-Schnittstelle mit vzlogger und einem IR-Schreib-Lesekopf abzufragen, muss die vzlogger.conf unter /etc/ wie folgt aussehen.
Im Frontend des Volkszaehlers muss ein Kanal mit den Einstellungen „El. Energie (Zählerstand)“, Auflösung 1 und Style = „Steps“ für Bezug erstellt werden.
Weiter muss, bei Zweirichtungszählern, ein zweiter Kanal mit den Einstellungen „El. Energie (Zählerstand)“, Auflösung 1 und Style = „Steps“ für Einspeisung erstellt werden.
Die aktuellen Zählerstände unter 'Initialverbrauch' im entsprechenden Kanal eintragen.

{
  "retry": 0,
  "daemon": true,
  "verbosity": 15,
  "log": "/var/log/vzlogger.log",
  
"local": {
    "enabled": false,
    "port": 8080,
    "index": true,
    "timeout": 0,
    "buffer": 0
  },
  
"meters": [
    {
      "enabled": true,
      "allowskip": false,
      "interval": -1,
      "aggtime": -1,
      "aggfixedinterval": false,
      "channels": [
        {
          "uuid": "hier die UUID aus dem im Frontend erstellten Kanal für Bezug eintragen",
          "identifier": "1.8.0",
          "api": "volkszaehler",
          "middleware": "http://localhost/middleware.php",
          "aggmode": "none",
          "duplicates": 0
        },
        {
          "uuid": "hier die UUID aus dem im Frontend erstellten Kanal für Einspeisung eintragen",
          "identifier": "2.8.0",
          "api": "volkszaehler",
          "middleware": "http://localhost/middleware.php",
          "aggmode": "none",
          "duplicates": 0
        }
      ],
      "protocol": "d0",
      "device": "/dev/ttyUSB0",
      "pullseq": "2F3F210D0A",
      "baudrate": 300,
      "parity": "7e1",
      "read_timeout": 10
       }
  ]
}

vzlogger.conf für S0-Impulse

Um die S0-Impulse des ACE3000 an der IR-Schnittstelle mit vzlogger und einem IR-Schreib-Lesekopf abzufragen, muss die vzlogger.conf unter /etc/ wie folgt aussehen.
Im Frontend des Volkszaehlers muss ein Kanal mit den Einstellungen „El. Energie (S0-Impulse)“, Auflösung 1000 und Style = „Steps“ erstellt werden.

{
    "retry": 0,            // how long to sleep between failed requests, in seconds
    "daemon": true,        // run periodically
    "verbosity": 15,         // between 0 and 15
    "log": "/var/log/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 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
            "skip": false,                  // if enabled, errors when opening meter will lead to meter being ignored
            "protocol": "s0",
            "aggtime": 30,                 // aggregate all signals and give one update to middleware every 30 seconds
            "device": "/dev/ttyUSB0",   // oder /dev/ttyAMA0
            "channel": {
                "identifier": "Impulse",    // s0 meter knows "Impulse" and "Power"
                "uuid": "hier die erzeugte UUID aus dem Kanal im Frontend eintragen",
                "middleware": "http://localhost/middleware.php"
            }
        }
     ]
 }

Test mittels Hterm

In der Hterm-Konsole gibt man die Zeichen „/?!“ (Schrägstrich+Fragezeichen+Ausrufezeichen, ohne Anführungszeichen) ein, dabei drauf achten, das in Hterm bei 'Send on Enter': CR+LF eingestellt ist. Danach sollte der Stromzähler antworten. Dies sieht in etwa so aus

Da sich der ACE3000 nach der Intialisierungssequenz bemüßigt fühlt, S0-Impulse auf der Infrarot-Schnittstelle auszugeben, sollte nach Eingabe der Zeichen die <Enter>-Taste schnell gedrückt werden, ansonsten kollidiert die Anfrage mit den S0-Impulsen und der Zähler gibt keine Antwort.

Beispielantwort

/?! 
/ACE0\3k260V01.18 
F.F(00) 
C.1(1234567890123456) 
C.5.0(00) 
1.8.0(000285.4*kWh) 
2.8.0(000120.1*kWh) 
!

Die Ausgabe kann abweichen, da der Datenblock vom Hersteller auf die Wünsche des Netzbetreibers angepasst werden kann, näheres findet man im Handbuch auf Seite 27, Kapitel 4.3

PHP-Abfrage

Die nachfolgende Abfrage zeigt, wie man mit dem genannten Equipment die Daten des Zählers abfragen kann. Die Ausgabe benötigt ca. 6-10 Sekunden bis zur Anzeige. Die Variablenwerte können dann nach Wunsch in eigenen Projekten weiterverwendet werden.

<?php
  $zeilen = 8;                                                                    // es sollten soviele Zeilen abgefragt
                                                                                  // werden, dass die letzte Zeile ein
                                                                                  // ! Ausrufezeichen hat
  $fp = fsockopen('ip.adresse_oder_domain.extension', 7970, $errno, $errstr, 30); // Socket öffnen
  if (!$fp) {                                                                     // Fehler abfangen
    echo "$errstr ($errno)<br />\n";                                              // Fehler ausgeben
  } else {                                                                        // Abfrage Zählerdaten
    fwrite($fp, "/?!\r\n");                                                       // Initialisierungs-String schreiben
    $i=0;                                                                         // Zählvariable
    while ($i < $zeilen) {                                                        // Zählschleife
      $result[$i] = fgets($fp);                                                   // eine Zeile abfragen
      if(substr($result[$i],0,5)=='1.8.0') $bezug       = (float)substr($result[$i],6,8);
                                                                                  // Auswertung der Tarifkennung und 
      if(substr($result[$i],0,5)=='2.8.0') $einspeisung = (float)substr($result[$i],6,8); 
                                                                                  // Zuweisung zu den Variablen
      $i++;                                                                       // Variable hochzählen
    }
    fclose($fp);                                                                  // Socket schließen
  }

  // Daten ausgeben - alle Zeilen 
  for ($i=0; $i < $zeilen; $i++) {
    echo $result[$i]."<br />";
  }

  // Daten ausgeben - "Erntevariablen"
  echo "Einspeisung:  ".$bezug." kWh<br />";
  echo "Einspeisung:  ".$einspeisung." kWh<br />";
?>

Auf die Auswertung der Tarifkennung könnte man auch verzichten und einfach die Zeilennummer annehmen. Leider hat sich gezeigt, dass der Zähler hie und da eine Zeile mehr liefert (möglicherweise ein dazwischengerutschter S0-Impuls), was zu falschen Eintragungen führen würde. Die Auswertung der Tarifkennung verhindert das.

Das Auslesen einer fixen Anzahl von Zeilen hat gegenüber der ebenfalls möglichen Abfrage von Einzelzeichen den Vorteil, daß der Socket möglichst schnell wieder geschlossen wird. Bei mir ist die Abfrage nach 7 Sekunden erledigt.

Abfrage mit Bash-Script

Hier ein Beispiel für die Abfrage mit einem Bash-Script und Berechnung der „virtuellen“ Zähler Eigenverbrauch und Gesamtverbrauch. Außerdem sind sind in dem Script Maßnahmen enthalten die dafür sorgen das keine unnötigen doppelten Einträge geschrieben werden. Das Script läuft auf einem Raspberry Pi und wird per Cron jede Minute aufgerufen. Auf Grund von Problemen mit dem Einlesen von den USB-IR-Köpfen auf der Shell musste zu den Hack gegriffen werden (Danke Thorben), das Aufwecken in einem Hintergrundaufruf zu stecken. Die Laufzeit für die Abfrage beider Zähler liegt zwischen 18 und 26s.

#!/bin/bash

# script zum auslesen von 2 Zaehlern "Itron ACE3000 Typ260 
# mit 300Baud 7E1 only
# 1. Zaehler fuer Bezug und Einspeisung
# 2. Zaehler fuer Solaranalge Erzeugung
# Aufruf des Script jede Minute via cron
#
# Berechnung und Uebertragung von Eigenverbrauch und Gesamtverbrauch
# zur Berechung werden die vorhergehenden Werte benötigt
# Speicherung im Filesystem, zum Schutz des SD-Karte im Raspberry Pi
# wird ins tmpfs , hier "/run" geschrieben.

UUID_Z1="12345678-5af5-11e2-b07b-4719a189d23d"
UUID_Z2="12345678-5b4b-11e2-80e1-470f08ca1a5d"
UUID_Z3="12345678-5c12-11e2-bf45-d7ff2b4611b3"
UUID_E="12345678-5b4b-11e2-9a36-95c59de08aa0"
UUID_S="12345678-5b4b-11e2-8293-d3b227ca0237"


# Init ttyUSBx 
stty -F /dev/ttyUSB0 1:4:da7:a30:3:1c:7f:15:4:10:0:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
stty -F /dev/ttyUSB1 1:4:da7:a30:3:1c:7f:15:4:10:0:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0

                                                            # Hack zum Aufwecken der Zähler im Hintergrund
( sleep 1 ; echo -e "\x2f\x3f\x21\x0d\x0a" > /dev/ttyUSB0 ) &

while read -t8 line                                         # warten auf die Zaehlerausgabe
do                                                          # Bestaetigung nach dem Wecken nicht notwendig
  [[ "$line" =~ "1.8.0" ]] && Z1=${line:6:8}                # Wert fuer Bezug
  [[ "$line" =~ "2.8.0" ]] && Z2=${line:6:8}                # Wert fuer Einspeisung
done < /dev/ttyUSB0

                                                                 # Auslesen des 2. Zaehlers
( sleep 1 ; echo -e "\x2f\x3f\x21\x0d\x0a" > /dev/ttyUSB1 ) &
while read -t8 line
do
#  [[ "$line" =~ "1.8.0" ]] && Z2_in=${line:6:8}                 # wird hier nicht benoetigt
  [[ "$line" =~ "2.8.0" ]] && Z3=${line:6:8}                     # Wert fuer Erzeugung
done < /dev/ttyUSB1

# Eigenverbrauch ist die Differenz aus Erzeugung - Einspeisung
# da die Zaehler nicht synchon umschalten koennten negative Werte entstehen
# das fuehrt zu starken Anzeigefehlern
# deshalb wird ueberprueft, dass der Eigenverbrauch nicht kleiner als der vorhergehende Wert wird.
#

eigen_old=$(cat /run/eigen_old)
eigen=$(echo "scale=1; ($Z3 - $Z2)" | bc)                       # Eigenverbrauch von PV
[ -z "$eigen_old" ] && eigen_old=$eigen

if [ $(echo "if ($eigen >= $eigen_old) 1 else 0" | bc) -eq 1 ] ; then  # wenn alt - neu negativ
 echo $eigen > /run/eigen_old
else
  eigen=$eigen_old;                                                    # dann alten Wert behalten
fi


summe=$(echo "scale=1; ($Z1 + $eigen)" | bc)                    # Gesamtverbrauch


# Debug
datum=`date`
echo -n "$datum : from:$Z1, to:$Z2, pv:$Z3, mypv:$eigen, myall:$summe" >> /tmp/zaehlerlog
# /Debug

# merken der Werte im Filesystem um unnötige Einträge in der DB zu vermeiden

Z1_old=$(cat /run/Z1)
echo $Z1 > /run/Z1
Z2_old=$(cat /run/Z2)
echo $Z2 > /run/Z2
Z3_old=$(cat /run/Z3)
echo $Z3 > /run/Z3
E_old=$(cat /run/Eigen)
echo $eigen > /run/Eigen
S_old=$(cat /run/Summe)
echo $summe > /run/Summe

# pruefen ob sich die Werte geaendert haben, wenn nicht dann wird auch nichts in die DB geschrieben 

[ "$Z1" == "$Z1_old" ] && Z1=""
[ "$Z2" == "$Z2_old" ] && Z2=""
[ "$Z3" == "$Z3_old" ] && Z3=""
[ "$eigen" == "$E_old" ] && eigen=""
[ "$summe" == "$S_old" ] && summe=""

# Debug , wenn alle Zaehlerstaende unveraendert dann ein "*" anhängen
[ -z "$Z1$Z2$Z3$eigen$summe" ] && echo -n " *" >> /tmp/zaehlerlog
echo >> /tmp/zaehlerlog
# /Debug

# senden der Zaehlerstände an die Middleware wenn notwendig
# statt vzclient ist auch wget oder curl möglich

[ -z "$Z1" ] || /usr/local/bin/vzclient -u $UUID_Z1 add data value=$Z1 > /dev/null
[ -z "$Z2" ] || /usr/local/bin/vzclient -u $UUID_Z2 add data value=$Z2 > /dev/null
[ -z "$Z3" ] || /usr/local/bin/vzclient -u $UUID_Z3 add data value=$Z3 > /dev/null
[ -z "$eigen" ] || /usr/local/bin/vzclient -u $UUID_E add data value=$eigen > /dev/null
[ -z "$summe" ] || /usr/local/bin/vzclient -u $UUID_S add data value=$summe > /dev/null

Die Zeilen zwischen #Debug und #/Debug können auskommentiert werden. Sie erzeugen eine Log, in der man unter anderem sehen kann wie doppelte Einträge nicht versandt werden. Das Log liegt hier auf der SD-Karte und sollte längerfristig abgeschaltet werden.

Mon Feb 11 07:23:26 CET 2013 : from:011660.6, to:004314.1, pv:006401.2, mypv:2087.1, myall:13747.7
Mon Feb 11 07:24:25 CET 2013 : from:011660.8, to:004314.1, pv:006401.2, mypv:2087.1, myall:13747.9
Mon Feb 11 07:25:25 CET 2013 : from:011660.9, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.0
Mon Feb 11 07:26:26 CET 2013 : from:011661.1, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.2
Mon Feb 11 07:27:26 CET 2013 : from:011661.2, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.3
Mon Feb 11 07:28:14 CET 2013 : from:, to:, pv:006401.2, mypv:2087.1, myall: *
Mon Feb 11 07:29:25 CET 2013 : from:011661.5, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.6
Mon Feb 11 07:30:14 CET 2013 : from:, to:, pv:006401.2, mypv:2087.1, myall: *
Mon Feb 11 07:31:20 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8
Mon Feb 11 07:32:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:33:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:34:18 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:35:20 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:36:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:37:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:38:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:39:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:40:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:41:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:42:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:43:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:44:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:45:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:46:19 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:47:18 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:48:18 CET 2013 : from:011661.7, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.8 *
Mon Feb 11 07:49:19 CET 2013 : from:011661.8, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.9
Mon Feb 11 07:50:19 CET 2013 : from:011661.8, to:004314.1, pv:006401.2, mypv:2087.1, myall:13748.9 *
Mon Feb 11 07:51:25 CET 2013 : from:011661.9, to:004314.1, pv:006401.2, mypv:2087.1, myall:13749.0
Mon Feb 11 07:52:25 CET 2013 : from:011662.0, to:004314.1, pv:006401.2, mypv:2087.1, myall:13749.1
Mon Feb 11 07:53:25 CET 2013 : from:011662.2, to:004314.1, pv:006401.2, mypv:2087.1, myall:13749.3
Mon Feb 11 07:54:25 CET 2013 : from:011662.3, to:004314.1, pv:006401.2, mypv:2087.1, myall:13749.4
Mon Feb 11 07:55:26 CET 2013 : from:011662.5, to:004314.1, pv:006401.2, mypv:2087.1, myall:13749.6

Zeilen mit einem * am Ende enthalten vollständig redundante Werte. Unabhängig davon werden alle redundante Werte ( z.B. pv:006401.2) nur einmal in die DB geschrieben. Manchmal gibt es aus unbekannten Gründen Lesefehler bei dem einen oder anderen Zähler. Auf Grund der Überprüfung der absoluten Werte ist der Anzeigefehler aber zu vernachlässigen.

Python-Script für Testzwecke

Hier noch ein Script eines Users:

###
import serial

#init port (change device!)
port = serial.Serial('/dev/tty.SLAB_USBtoUART', 300, 7, 'E', 1) // für PC: port = serial.Serial('/dev/ttyUSB0', 300, 7, 'E', 1)

#write "\!?"+CR+LF to port to init D0-Mode of the Itron ACE3000
port.write("\x2f\x3f\x21\x0d\x0a")

#debug: output each line
#while True:
#       print(port.readline())

#search line with kwh, normally this takes 6-7 line-reads
line = ''
while not '1.8.0(' in line:
        line=port.readline()
        #print(line)
        print('No line with kWh found, proceed with next line...')

if  '1.8.0(' in line:
        print('Found line with kWh.')
        #print(line)
        #typecast substring of line to float
        try:
                value = float(line[6:14])
                print('Current meter reading: %0.1f kWh' % value)
        except:
                print('ERROR : No value found!');
else:
        print('ERROR: No line with kWh found at all.')
###
hardware/channels/meters/power/edl-ehz/itron_ace3000_type_260.txt · Zuletzt geändert: 2017/05/06 15:06 von jau