Gaszähler auslesen

Nachdem meine Versuche den M-BUS Wärmemengen- und Wasserzähler auszulesen vorerst beendet sind und ich auf den bestellten M-BUS-Pegelwandler warte, habe ich mich dem Auslesen des Gaszählers gewidmet. Das sollte erfolgsversprechender sein…

Als ich dann endlich den vor langer Zeit bestellten Reed-Kontakt mk 471 b (z.B. bei Reichelt) wieder gefunden habe, konnte es losgehen.

Der Gaszähler hat an der letzten Stelle des Zählwerkes bei der “0” einen Magneten wodurch der Reedkontakt bei jeder vollen Umdrehung einmal geschlossen wird. Diese Impulse gilt es mit einem Raspberry über einen GPIO zu zählen.

IMG_7735

Den Reedkontakt habe ich natürlich wieder professionell mit Klebeband fixiert…hält!

IMG_7734

Angeschlossen ist der Reedkontakt über eine Zwillingslitze direkt an einen GPIO und Ground des Raspberry PI. Pull-Up braucht es keinen. Dieser wird per Software aktiviert.

Den GPIO lese ich mit einem Python-Script aus welches in einer Endlosschleife ausgeführt wird und den GPIO (im Beispiel Pin “21”) jede Sekunde abfragt. Sekundenweise sollte reichen, da ich nicht hoffe das unser Gaszähler so schnell läuft. Immer wenn der Reed geschlossen wird, wird eine “1” und der Zeitstempel in die Spalten “timestamp” und “zaehlerstand” einer MySQL-Tabelle geschrieben. Das passiert immer nur beim Wechsel des Reed von “Offen” nach “Geschlossen”. Sollte der Zähler genau mit dem Magnet am Reed stehen bleiben, passiert nichts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import RPi.GPIO as GPIO
import time
import MySQLdb

GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

# GPIO definieren
REED_gas = 21
# definierten GPIO als Eingang setzen
GPIO.setup(REED_gas, GPIO.IN, pull_up_down=GPIO.PUD_UP)

status_alt=1
while True:
    status_aktuell = GPIO.input(REED_gas)
    # REEDKONTAKT geoeffnet
    if status_aktuell == 1:
        #print "Kontakt offen"
        status_alt=GPIO.input(REED_gas)
        # REEDKONTAKT geschlossen
    elif status_aktuell==0:
        #print "Kontakt geschlossen"
        if status_alt!=status_aktuell:
            status_alt=GPIO.input(REED_gas)
            # Datenbankverbindung
            db = MySQLdb.connect(host="<host>", user="<benutzer>", passwd="<passwort>", db="<datenbank>")
            # Impuls in Datenbank eintragen
            cursor = db.cursor()
            cursor.execute("""INSERT INTO gaszaehler (timestamp,zaehlerstand) VALUES (CURRENT_TIMESTAMP,1)""")
            db.commit()
            cursor.close()
    time.sleep(1)

IMG_7737

Da das Python-Script sich ab und an mal verabschiedet, starte ich es per Cronjob wieder neu falls der Prozess nicht mehr vorhanden ist. Ich sollte vielleicht lieber das Problem im Python-Script suchen und das ein oder andere Try&Catch einbauen, aber es geht auch erstmal so…

Zur Auswertung benutze ich dann folgende SQL-Querys:

Hiermit werden alle gespeicherten “Ticks” summiert. Dazu muss noch ein Startwert addiert werden da der Gaszähler ja schon eine zeitlang lief.
Dieser Startwert muss ggf. ab und an mal korrigiert werden falls der Raspi mal einen Umlauf des Zählers nicht mitbekommt weil z.B. der unwahrscheinliche Fall eintritt, dass das Klebeband nicht gehalten hat oder wahrscheinlicher, das Python-Script bzw. der ganze Raspi nicht mehr läuft. Den Startwert gebe ich als eine Zahl inkl. der drei Nachkommastellen an und addiere das Ergebnis der SQL-Query dazu. Um die richtige “Einheit” kümmere ich mich in der Ausgabe auf der PHP-Seite mit folgender PHP-Zeile:

1
2
3
4
5
6
$sql = "SELECT sum(zaehlerstand) FROM gaszaehler";
$query = mysql_query($sql) or die("Anfrage nicht erfolgreich");
while ($wert = mysql_fetch_array($query)) {
    $gesamtwert=($wert[0]*10)+$gas_startwert;
}
$gesamtwert=substr($gesamtwert,0,-3).".".substr($gesamtwert,-3,2);

Der Faktor 10 muss hier beachtet werden, da ja nur alle 0,01m³ Impulse gezählt werden und ich den Startwert mit allen drei Nachkommastellen angegeben habe. Die zweite Zeile setzt das Komma in der Ausgabe an die richtige Stelle.

Eine tägliche Auswertung funktioniert z.B. mit folgender SQL-Query:

Auch hier bekommt man den korrekten Wert in m³ durch einfache Kommaverschieberei in der Ausgabe. Den Faktor 10 benötigt man bei der täglichen Auswertung nicht:

1
substr(($wert[1]),0,-2).".".substr(($wert[1]),-2)

In der Webseite sieht das folgendermaßen aus:

gaszaehler_screenshot

Das alles läuft erst drei Tage und es gibt bestimmt noch Verbesserungspotential aber ein Anfang ist gemacht.

Gruß
Chris

13 Gedanken zu „Gaszähler auslesen

  • 25. November 2014 um 21:30
    Permalink

    Hi,
    super beschrieben, genau das Projekt was ich auch “versuche” umzusetzen. Gibt es da auch die Möglichkeit die ausgelesenen daten in eine RRD Datenbank abzulegen. zur Zeit habe ich Temperatur Daten meiner Heizungsanlage über OneWire in den RRDs, würde gerne auch Gaszaehleraten dort unterbringen. Wie ich jedoch statt mysql RRD einsetze weiss ich noch nicht ??
    Gruß ….. Gerd

    Antwort
    • diefenbecker
      28. November 2014 um 18:09
      Permalink

      Hallo Gerd,

      ich kenne mich mit rrd leider nicht so gut aus, denke aber das Du dort einen absoluten Wert benötigst (z.B. Tagesverbrauch) anstatt der 0,01m³-Impulse.
      Ein erster Ansatz wäre evtl. die einzelnen Impulse des Python-Scripts mit Zeitstempel in einer Textdatei zeilenweise zu speichern. Diese Daten aus der Textdatei könntest Du dann mit einem zweiten Script einmal täglich anhand des Zeitstempels aufsummieren und das Ergebnis dann in die rrd schreiben (und evtl. die Textdatei wieder löschen um immer nur einen Tag darin zu speichern).

      Vielleicht hilft Dir das ja schon mal weiter!

      Gruß
      Chris

      Antwort
  • 12. Dezember 2014 um 21:58
    Permalink

    Hallo Chris,
    habe nun endlich meine SQL Datenbank eingerichtet, jedoch tun sich diverse Fehler oder Fragen auf. Vielleicht kannst Du helfen.
    1. habe das py script angepasst
    import RPi.GPIO as GPIO
    import time
    #import MySQLdb
    import gaszaehler

    GPIO.setmode(GPIO.BOARD)
    GPIO.setwarnings(False)

    # GPIO definieren
    REED_gas = 10
    # definierten GPIO als Eingang setzen
    GPIO.setup(REED_gas, GPIO.IN, pull_up_down=GPIO.PUD_UP)

    # Datenbankverbindung
    db = gaszaehler(host=”localhost”, user=”pi”, passwd=”XXXXXXX”, db=”gaszaehler”)

    status_alt=1
    while True:
    status_aktuell = GPIO.input(REED_gas)
    # REEDKONTAKT geoeffnet
    if status_aktuell == 1:
    #print “Kontakt offen”
    status_alt=GPIO.input(REED_gas)
    # REEDKONTAKT geschlossen
    elif status_aktuell==0:
    #print “Kontakt geschlossen”
    if status_alt!=status_aktuell:
    status_alt=GPIO.input(REED_gas)
    # Impuls in Datenbank eintragen
    cursor = db.cursor()
    cursor.execute(“””INSERT INTO gaszaehler (timestamp,zaehlerstand) VALUES (CURRENT_TIMESTAMP,1)”””)
    db.commit()
    cursor.close()
    time.sleep(1)
    ————
    pi@vdr ~/temperatur/gaszaehler $ sudo python gaszaehler.py
    Traceback (most recent call last):
    File “gaszaehler.py”, line 4, in
    import gaszaehler
    File “/home/pi/temperatur/gaszaehler/gaszaehler.py”, line 15, in
    db = gaszaehler(host=”localhost”, user=”pi”, passwd=”XXXXXXX”, db=”gaszaehler”)
    TypeError: ‘module’ object is not callable
    ————
    1. nach dem start sollte sich eigentlich die db füllen? und dann?
    2. Was bedeutet die Fehlermeldung , hab ich da was in der DB falsch eingerichtet?

    Antwort
  • 14. Januar 2015 um 10:44
    Permalink

    Hallo,
    vielen Dank für die Ideen.
    Bekommst du auch immer 2 Impulse pro Umdrehung? Ich bekomme eine Impuls, wenn ich die 1 und die 9 im Sichtfenster sehe.
    Bei mir registriert eine Interrupt Service Routine die Impulse und schreibt dann in die DB.
    Hast du eine Idee wie man eine tägliche Auswertung in SQLite machen kann?
    Danke im Voraus.

    Antwort
    • diefenbecker
      17. Januar 2015 um 11:45
      Permalink

      Hi Felix,

      nein, bei mir wir immer nur ein Impuls pro Umdrehung gezählt. Vielleicht zählst Du das Schliessen und Öffnen des Kontaktes?
      Du musst auch dafür sorgen, das nur ein Impuls gezählt wird solange der Magnet genau am Kontakt stehen bleibt.

      Kenne leider SQLite nicht im Detail aber das sollte doch auch normales ANSI SQL verstehen, oder?
      Hab mir das mal kurz angeschaut und gesehen, dass auch “CURRENT_TIMESTAMP” unterstützt wird.
      Was genau funktioniert denn nicht?

      Gruß
      Chris

      Antwort
  • 22. Januar 2015 um 10:28
    Permalink

    Hallo,
    “zählst du da Schliessen *und* Öffnen”, mmmhh. Ich habe den Pin genauso wie du gesetzt.
    Das mit der täglichen Auswertung in SQLite sieht bei mir so aus:
    SELECT tstamp,
    CASE CAST (strftime(‘%w’, tstamp) as integer)
    WHEN 1 THEN ‘Monday’
    WHEN 2 THEN ‘Tuesday’
    WHEN 3 THEN ‘Wednesday’
    WHEN 4 THEN ‘Thursday’
    WHEN 5 THEN ‘Friday’
    WHEN 6 THEN ‘Saturday’
    WHEN 0 THEN ‘Sunday’
    ELSE ‘fehler’ END,
    SUM(tick)
    FROM gascounter WHERE tstamp BETWEEN DATE(‘now’, ‘-7 days’) AND DATE(‘now’)
    GROUP BY strftime(‘%w’, tstamp)
    ORDER BY tstamp

    Antwort
    • diefenbecker
      23. Januar 2015 um 16:12
      Permalink

      Hi,
      das Script schreibt immer nur einen Impuls in die Datenbank wenn ein “geschlossen” auf ein vorheriges “offen” folgt.
      Bleibt es “geschlossen” während die Schleife erneut durchlaufen wird (z.b. weil der Magnet genau in der Position stehen bleibt) oder ist es “offen”, wird nicht gezählt.

      Gruß
      Chris

      Antwort
      • 23. Januar 2015 um 19:57
        Permalink

        Hallo Chris,
        ja, schon verstanden. Ich habe deinen Code auch bei mir laufen lassen. Tat aber nicht….
        Ich schau weiter.
        Grüße

        Antwort
  • Pingback: Gaszähler auslesen - Darstellung der Daten - bubuxblog

  • 13. Oktober 2017 um 10:29
    Permalink

    Hallo Chris,
    auch wenn das Thema und die letzten Kommentare ein paar Tage alt sind, wollte ich mich trotzdem für die Zusammenstellung bedanken. Habe das Ganze bei mir zuhause nachgebaut.

    Dabei ist mir in den Restart-Logs für das Python-Script aufgefallen, dass die Abstürze immer auftreten, nachdem das Script eine längere Zeit nichts gemacht hat. Ich vermute die Ursache liegt im Verbindungsaufbau außerhalb der WHILE-Schleife. Wird lange Zeit nichts in die DB geschrieben, beendet die DB die Verbindung und beim nächsten Schreibversuch stürzt das Script ab.
    Ich habe es mir relativ einfach gemacht und die Connection-Zeit der Datenbank entsprechend erhöht. Das Script läuft mittlerweile eine Woche ohne einen Absturz.
    Alternativ könnte man den Verbindungsaufbau zur Datenbank wahrscheinlich auch mit in die While-Schleife aufnehmen und die Connection in der Schleife auch wieder beenden.

    Viele Grüße
    Boris

    Antwort
    • diefenbecker
      13. Oktober 2017 um 15:08
      Permalink

      Hi Boris,

      Du hast recht! Ich habe die gleichen Probleme gehabt und das Connect in die while aufgenommen, damals aber leider nicht im Blog geändert was ich nun nachgeholt habe.
      Vielen Dank für den Hinweis!

      Gruß
      Chris

      Antwort
  • 15. März 2018 um 13:36
    Permalink

    Ich bin mit meinen 65 Jahren am Ende.
    Wie muss die Datenbank aussehen. Einfach per Befehl die DB anlegen, oder ????

    M.f.G manfred

    Antwort

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.