Stromzähler auslesen und in Homematic integrieren - wget

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Awacs2000
User
Beiträge: 7
Registriert: Sonntag 11. Januar 2015, 14:46

Hallo zusammen!

Ich würde gerne meine EDL21-Stromzählerdaten in Systemvariablen in meiner Homematic CCU2 anzeigen lassen bzw. in Systemvariablen auf der Homematic schreiben lassen.
Von Skripten habe ich leider keinerlei Ahnung.

Ich habe jedoch ein Skript vorliegen, welchen meinen Stromzähler aktuell auslesen kann. Das ganze läuft aktuell auf einem Raspberry und gehört zu einem Energiemanagement-Projekt, an dem ich
als Testperson teilgenommen hatte.
Dort wird der Stromzähler per Schreiblesekopf (com.met COM-IR) per TCP über Port 5000 ausgelesen und in eine Datenbank gespeichert und dann später per HTML angezeigt.
Ich möchte nun aber die Werte nicht in eine MySQL-Datenbank schreiben lassen, sondern mit DB-Access der CCU verknüpfen.
Das habe ich aktuell schon mit den Daten meiner PV-Anlage.Allerdings ist das eien Bash-Skript und dort werden die Daten mit wget gesendet. Das funktioniert auch wunderbar.

Code: Alles auswählen

#
#   define common parameters for wget
#
COMMONWGETARGS="-q -O - --timeout=10"
:
wget $COMMONWGETARGS --http-user=<username> --http-password=<password> "http://inverter1.site/index.fhtml" | sed -e "s/nbsp/nbsp;/g" | sed -e "s/nbsp;;/nbsp;/g" | sed -e "s/\&nbsp;//g" | html2text | tr -s " \t\r\n" | sed -e "s/^ //" | sed -e "s/x x x/0/g" >/tmp/power-inverter1.values
PHOTOVOLTAICS_DC1U=$( cat /tmp/power-inverter1.values | grep Spannung | head -1 | cut -f2 -d" " )
PHOTOVOLTAICS_DC2U=$( cat /tmp/power-inverter1.values | grep Spannung | head -2 | tail -1 | cut -f2 -d" " )
PHOTOVOLTAICS_DC1I=$( cat /tmp/power-inverter1.values | grep Strom | head -1 | cut -f2 -d" " | awk '{printf "%d\n",$1*1000}' )
PHOTOVOLTAICS_DC2I=$( cat /tmp/power-inverter1.values | grep Strom | head -2 | tail -1 | cut -f2 -d" " | awk '{printf "%d\n",$1*1000}' )
PHOTOVOLTAICS_DC1P=$(( $PHOTOVOLTAICS_DC1U * $PHOTOVOLTAICS_DC1I / 1000 ))
PHOTOVOLTAICS_DC2P=$(( $PHOTOVOLTAICS_DC2U * $PHOTOVOLTAICS_DC2I / 1000 ))

PHOTOVOLTAICS_ACCURP=$( cat /tmp/power-inverter1.values | grep aktuell | cut -f2 -d" " )
PHOTOVOLTAICS_ACTOTP=$( cat /tmp/power-inverter1.values | grep Gesamtenergie | cut -f5 -d" " )
PHOTOVOLTAICS_DAILYP=$( cat /tmp/power-inverter1.values | grep Tagesenergie | cut -f2 -d" " )
:
#
#   update the system variables in the HomeMatic
#
wget $COMMONWGETARGS "http://homematic.site/addons/db/state.cgi?item=PV.DC1&value=$PHOTOVOLTAICS_DC1P"
wget $COMMONWGETARGS "http://homematic.site/addons/db/state.cgi?item=PV.DC2&value=$PHOTOVOLTAICS_DC2P"
wget $COMMONWGETARGS "http://homematic.site/addons/db/state.cgi?item=PV.AC&value=$PHOTOVOLTAICS_ACCURP"
wget $COMMONWGETARGS "http://homematic.site/addons/db/state.cgi?item=PV.DAILYP&value=$PHOTOVOLTAICS_DAILYP"
Prinzipiell müste ich jetzt nur wissen, wie man die, in meinem vorliegenden Skript, Variablen Zaehlerstand, Wirkleistung usw. von meinem Skript verlinkt bekommt mit den Variablen in DB-Access auf der Homematic. Dort habe ich aktuell z.B. schon die Variable "Zaehlerstand" angelegt.
Wie in dem, oben aufgeführten, Skript (wget $COMMONWGETARGS "http://homematic.site/addons/db/state.c ... TAICS_DC1P"), nur eben in Python-Sprache.


Wenn mein Skript gestartet wird sieht das Ergebnis in Putty so aus:

Code: Alles auswählen

Reading Smart Meter Stream
Get Information from Smart Meter Stream
Zaehlerstand Methode A
Zaehlerstands Index mit Methode A
Index A: 22 Index B: 50
Zaehlerstand (HEX) : 0000000001CC7CFF
[b]Zaehlerstand :[/b] 3017
Wirkleistung Methode A
Wirkleistungs Index mit Methode A
Wirkleistung (HEX) : 00000115
[b]Wirkleistung : [/b]277.0 W
Zaehlerstand Produktion gefunden
Zaehlerstand Produktion Index mit Methode A
Z. Produktion (HEX) : 0000000007BA0F7E
[b]Z.Produktion : [/b]12963.0
2015-01-10 14:41:13.879632
Save Prod
Save Smart Meter Values to Database
INSERT INTO smart_meter_values (time,vendorid, serverid, wirkarbeittot, wirkleistung, wirkarbeitdelta, production) VALUES ('2015-01-10 14:41:13.879632','0','localhost','3017','277.0','0.0','12963.0')
Saved Successfull
Das Skript dazu sieht in etwa folgendermasen aus:

Code: Alles auswählen

#!/usr/bin/python

# Auslesen EDL21 per IR-Lesekopf



def prodSystem():
        #0 Nein
        #1 Ja
        return 1

import time
import pytz
import socket
from datetime import datetime, timedelta
def read_smart_meter():
        print "Reading Smart Meter Stream"
        TCP_IP = "192.168.126.129"
        TCP_PORT = 5000
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((TCP_IP, TCP_PORT))
        dataBuffer = s.recv(1024)
        data = s.recv(10000)
        #print data
        openbreak = 0
        openbreak = data.index("(")
        openbreak = openbreak + 1
        closingbreak = data.index(")")
        smlfilelength = closingbreak - openbreak
        smlmsg = data[openbreak:openbreak+smlfilelength]
        s.close()
        calc_smart_meter(smlmsg)

def simulate_read_smart_meter():
        #Daten Lesekopf
        simulate_smart = "1B1B1B1B01010101760501FDE17462006200726301017601010
500A9F5D00B090149534B0003C1DB01010163F62400760501FDE175620062007263070177010B
090149534B0003C1DB01070100620AFFFF7262016500FB06907D77078181C78203FF010101010
449534B0177070100000009FF010101010B090149534B0003C1DB010177070100010800FF6500
01018201621E52FF5900000000008698BC0177070100010801FF0101621E52FF5900000000008
698BC0177070100010802FF0101621E52FF5900000000000000000177070100020800FF650001
018201621E52FF590000000002E6A1840177070100020801FF0101621E52FF590000000002E6A
1840177070100020802FF0101621E52FF5900000000000000000177070100100700FF0101621B
520055000003600177070100240700FF0101621B5200550000006A0177070100380700FF01016
21B520055000002D101770701004C0700FF0101621B520055000000240177078181C78205FF01
0101018302D9C7AD5BF636D3DD352E689E9EDF9EE83A2CE552649CE5E4323FFF16A838F704B3F
8C0806B2C646C2957CA9BF0F6397901010163CEAF00760501FDE1766200620072630201710163FBEE001B1B1B1B1A00871"

        calc_smart_meter(simulate_smart)

def calc_smart_meter(smart_stream):
        zaehlerstand = 0
        wirkleistung = 0
        #print smart_stream
        print "Get Information from Smart Meter Stream"

        j = 0
        if "0100010800FF" in smart_stream:
                print "Zaehlerstand Methode A"
                try:
                        j = smart_stream.index("0100010800FF")
                        zahlerstandHEX = smart_stream[j:j+100]
                        j2 = 0
                        j3 = 0
                        if "01621E52FF59" in zahlerstandHEX:
                                print "Zaehlerstands Index mit Methode A"
                                j2 = zahlerstandHEX.index("01621E52FF59")
                                j3 = zahlerstandHEX.index("017707")
                                print "Index A: %s Index B: %s" % (j2,j3)
                                ZS_HEX = zahlerstandHEX[(j2+12):j3]
                                print "Zaehlerstand (HEX) : %s" % ZS_HEX
                                decZS = int(ZS_HEX,16)
                                zaehlerstand = (decZS / 10000)
                                print "Zaehlerstand : %s" % zaehlerstand
                        elif "01621E52FF56" in zahlerstandHEX:
                                print "Zaehlerstands Index mit Methode B"
                                j2 = zahlerstandHEX.index("01621E52FF56")
                                j3 = zahlerstandHEX.index("017707")
                                ZS_HEX = zahlerstandHEX[(j2+12):j3]
								                                print "Zaehlerstand (HEX) : %s" % ZS_HEX
                                decZS = int(ZS_HEX,16)
                                zaehlerstand = (decZS / 10000)
                                print "Zaehlerstand : %s" % zaehlerstand
                        else:
                                print "Konnte den Zaehlerstand nicht finden"
                except:
                        print "Fehler in Methode A beim Zaehlerstand"
        elif "0100010801FF" in smart_stream:
                print "Zaehlerstand Methode B"
                try:
                        j = smart_stream.index("0100010801FF")
                        zahlerstandHEX = smart_stream[j:j+100]
                        j2 = 0
                        j3 = 0
                        if "01621E52FF69" in zahlerstandHEX:
                                print "Zaehlerstands Index mit Methode A"
                                j2 = zahlerstandHEX.index("01621E52FF69")
                                j3 = zahlerstandHEX.index("017707")
                                print "Index A: %s Index B: %s" % (j2,j3)
                                ZS_HEX = zahlerstandHEX[(j2+12):j3]
                                print "Zaehlerstand (HEX) : %s" % ZS_HEX
                                decZS = int(ZS_HEX,16)
                                zaehlerstand = (decZS / 10000)
                                print "Zaehlerstand : %s" % zaehlerstand
                        else:
                                print "Konnte den Zaehlerstand nicht finden"
                except:
                        print "Fehler in Methode A beim Zaehlerstand"
        elif "jh" in smart_stream:
                print "Zaehlerstand Methode C"
        else:
                print "Zaehlerstand nicht Abrufbar"
                zaehlerstand = 0

        k = 0
        if "0100100700FF" in smart_stream:
                print "Wirkleistung Methode A"
                try:
			                        k = smart_stream.index("0100100700FF")
                        wirkleistungHEX = smart_stream[k:k+100]
                        k2 = 0
                        k3 = 0
                        if "55" in wirkleistungHEX:
                                print "Wirkleistungs Index mit Methode A"
                                k2 = wirkleistungHEX.index("55")
                                k3 = wirkleistungHEX.index("017707")
                                WL_HEX = wirkleistungHEX[k2+2:k3]
                                print "Wirkleistung (HEX) : %s" % WL_HEX
                                decWL = int(WL_HEX,16)
                                if WL_HEX[0:2] == "FF":
                                        decWLL = int("FFFFFFFF", 16)
                                        print "FULL: %s" % decWLL
                                        print "CURR: %s" % decWL
                                        decWL = decWL-decWLL
                                wirkleistung = float(decWL);
                                print "Wirkleistung  : %s W" % wirkleistung
                        elif "3423432" in wirkleistungHEX:
                                print "Wirkleistungs Index mit Methode B"
                        else:
                                print "Konnte die Wirkleistung nicht finden"
                except:
                        print "Fehler in Methode A beim Zaehlerstand"

        elif "01000F0700FF" in smart_stream:
                print "Wirkleistung Methode B"
                try:
                        k = smart_stream.index("01000F0700FF")
                        wirkleistungHEX = smart_stream[k:k+100]
                        k2 = 0
                        k3 = 0
                        if "55" in wirkleistungHEX:
                                print "Wirkleistungs Index mit Methode A"
                                k2 = wirkleistungHEX.index("55")
                                k3 = wirkleistungHEX.index("017707")
                                WL_HEX = wirkleistungHEX[k2+2:k3]
                                decWL = int(WL_HEX,16)
                                print "Wirkleistung (HEX) : %s" % WL_HEX
                              wirkleistung = float(decWL);
                                print "Wirkleistung  : %s W" % wirkleistung
                        elif "932323" in wirkleistungHEX:
                                print "Wirkleistungs Index mit Methode B"
                        else:
                                print "Konnte die Wirkleistung nicht finden"
                except:
                        print "Fehler in Methode B beim Zaehlerstand"
        elif "0100010700FF" in smart_stream:
                print "Wirkleistung Methode C"
                try:
                        k = smart_stream.index("0100010700FF")
                        wirkleistungHEX = smart_stream[k:k+50]
                        k2 = 0
                        if "55" in wirkleistungHEX:
                                print "Wirkleistungs Index mit Methode A"
                                k2 = wirkleistungHEX.index("55")
                                WL_HEX = wirkleistungHEX[k2+2:k2+10]
                                decWL = int(WL_HEX,16)
                                print "Wirkleistung (HEX) : %s" % WL_HEX
                                wirkleistung = float(decWL);
                                print "Wirkleistung  : %s W" % wirkleistung
                        elif "932323" in wirkleistungHEX:
                                print "Wirkleistungs Index mit Methode B"
                        else:
                                print "Konnte die Wirkleistung nicht finden"
                except:
                        print "Fehler in Methode C beim Zaehlerstand"
        else:
                print "Wirkleistung nicht Abrufbar"
                wirkleistung = 0

        if prodSystem() == 1:
                x = 0
                if "0100020800FF" in smart_stream:
                        print "Zaehlerstand Produktion gefunden"
                        x = smart_stream.index("0100020800FF")
                        prodZaHEX = smart_stream[x:x+100]
                        x2 = 0
                        x3 = 0
                        if "01621E52FF59" in prodZaHEX:
                                print "Zaehlerstand Produktion Index mit Methode A"
                                x2 = prodZaHEX.index("01621E52FF59")
                                x3 = prodZaHEX.index("017707")
                                PZ_HEX = prodZaHEX[x2+12:x3]
                                decWL = int(PZ_HEX,16)
                                print "Z. Produktion (HEX) : %s" % PZ_HEX
                                zaehlerprod = float(decWL/10000);
                                print "Z.Produktion  : %s" % zaehlerprod
                        else:
                                print "Konnte die Zaehlerstand Produktion  nicht finden"
                else:
                        print "Produktion nicht abrufbar"

        #berlinTZInt = pytz.timezone('Europe/Berlin')
        #currentTimeBerlinInt = datetime.now(berlinTZInt)
        #currentTimeBerlinInt = currentTimeBerlinInt.replace(tzinfo=None)
        #print currentTimeBerlinInt
        #cnx = mysql.connector.connect(**config)
        #cursorModule = cnx.cursor()
        queryModule = ("select wirkarbeittot from smart_meter_values where time=(select max(time) from smart_meter_values)")
        #cursorModule.execute(queryModule)
        lastWirk = 0
        for wirkarbeittot in cursorModule:
                lastWirk = wirkarbeittot[0]

        wirkarbeitDelta = 0
        if lastWirk >= 0:
                    wirkarbeitDelta = (zaehlerstand - lastWirk)
        else:
                    wirkarbeitDelta = 0
        if prodSystem() == 1:
                print "Save Prod"
                save_smart_meter_db_prod(currentTimeBerlinInt, 0,'localhost',zaehlerstand,wirkleistung,wirkarbeitDelta, zaehlerprod)
        else:
                print "Save Normal"
                save_smart_meter_db(currentTimeBerlinInt, 0,'localhost',zaehlerstand,wirkleistung,wirkarbeitDelta)
def save_smart_meter_db(time, vendorid, serverid, wirktot, wirklei, wirkdelta):
        print "Save Smart Meter Values to Database"
        #cnx = mysql.connector.connect(**config)
        #cursor = cnx.cursor()
                query = """INSERT INTO smart_meter_values (time,vendorid, serverid, wirkarbeittot, wirkleistung, wirkarbeitdelta) VALUES ('%s','%s','%s','%s','%s','%s')"""  % (time,vendorid,serverid,wirktot,wirklei,wirkdelta)
        print query
        cursor.execute(query)
        cursor.close()
        #cnx.commit()
        #cnx.close()
        print "Saved Successfull"

def save_smart_meter_db_prod(time, vendorid, serverid, wirktot, wirklei, wirkdelta,prod):
        print "Save Smart Meter Values to Database"
        #cnx = mysql.connector.connect(**config)
        #cursor = cnx.cursor()
                query = "delete from smart_meter_values where id NOT IN(select id from (select DISTINCT smart_meter_values.id from smart_meter_values group by year(time),month(time),day(time),hour(time)) as tmptable)"
        print query
        cursor.execute(query)
        cursor.close()
        #cnx.commit()
        #cnx.close()
        print "Saved Successfull"

timer = 0
while(1>0):
        read_smart_meter()
        timer = timer + 1
        if(timer>=5000):
                timer = 0
                #cnx = mysql.connector.connect(**config)
                #cursor = cnx.cursor()
                query = "delete from smart_meter_values where id NOT IN(select id from (select DISTINCT smart_meter_values.i$
                cursor.execute(query)
                cursor.close()
                #cnx.commit()
                #cnx.close()
        time.sleep(2)
Ich bin dankbar für jede Hilfe.
Wie gesagt, von Skrpten so gut wie keine Ahnung. Mit guten Tipps und Iden würde ich aber evtl. weiterkommen.
Zuletzt geändert von Hyperion am Sonntag 11. Januar 2015, 15:42, insgesamt 1-mal geändert.
Grund: Code und Ausgaben in Tags entsprechende Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich habe ehrlich gesagt nicht verstanden, was Du jetzt von uns möchtest! Also an welcher Stelle hakt es usw. Vielleicht braucht es da doch mal eine kleinere Skizze, die erklärt, wie das ganze System zusammenhängt und wo Deine Python-Komponente eingebunden ist und *was* diese tun soll.

Ehrlich gesagt sieht Dein Python-Script wirklich danach aus, als hättest Du keine Ahnung. Nicht bös gemeint, aber da fehlt es an allen Ecken und Enden an Basiswissen über Programmierung und Softwareentwicklung i.A. Ich denke durch so ein Monstrum will und kann sich keiner hier durcharbeiten; zumal das Script an sich so ja nicht lauffähig sein dürfte (einige externe Abhängigkeiten).

Ich denke für konkrete Hilfe müsstest Du Deine Frage konkretisieren und vor allem einen Anhaltspunkt liefern, wo etwas passieren soll.

Bitte achte in Zukunft darauf, Quellcode in die dafür vorgesehenen Tags zu setzen. Ansonsten ist der Code nicht zu lesen, da z.B. die Einrückungen wegfallen, die in Python sogar integraler Bestandteil der Syntax sind.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Awacs2000
User
Beiträge: 7
Registriert: Sonntag 11. Januar 2015, 14:46

Ist für mich auch nicht ganz einfach zu erklären.
Also zunächst einmal habe ja nicht ich das Skript geschrieben. Das ganze war Teil eines Uni-Projektes, an dem ich als Testuser teilgenommen habe.
Dieses Skript läuft auf einem Raspberry und stellt mir die ausgelesen Daten meines Stromzählers grafisch in einem Tool dar.
Das klappt auch problemlos. In dem Projekt ging es um Energiemanagement usw.

Ich habe diese Skript nun auf dem Raspberry gefunden, weil mir der ursprüngliche Programmierer mal irgendwann das Kennwort gegeben hat.
Das Skript sieht wohl deshalb nicht lauffähig aus, weil ich schon einige Zeilen (SQL usw) testweise weggelöscht hatte bzw. rausgenomen hatte (#). Sorry dafür.
Letzten Endes funktioniert es aber, wie man ja in meinem Thread sehen kann. Den Zählerstand usw. kann das Skript ja problemlos auslesen und in eine Datenbank schreiben.

Ich möchte aber nun die ausgelesenen Daten, wie z.B. den aktuellen Zählerstand, in meine Homematic-Haussteuerungszentrale einbinden.
Wie schon erwähnt werden momentan schon die Daten meiner Photovoltaikanlage ausgelesen (mit dem anderen Skript, welches ja kein Python ist und ebenso auch nicht von mir stammt, sonderm aus einem Homematic-Forum) und in die Homematic geschrieben. Dort läuft ein kleines Add-On namens DB-Access.

Auf der Homematic sind Systemvariablen angelegt und die erfassten Messdaten werden dort hineingeschrieben und auf der Weboberfläche somit dargestellt.
Mit den Variablen kann man in der Homematic natürlich weiterarbeiten. "Mach mir z.B. nur die Klimaanlage im Sommer an, wenn mehr als 6000kW/h produziert werden" und so weiter.
Mit den Stromzählerdaten möchte ich eigentlich nichts anfangen, sondern diese nur visuell in der Haussteuerung an zentraler Stelle sehen und nicht mehr in dem Tool des oben erwähneten Projektes, da der Raspberry auch schon mal gerne den Geist aufgibt und weil das Projekt nicht mehr weiterverfolgt bzw. supportet wird.

Also, welche Fragen habe ich:

- Wie bekomme ich die Daten, welches das Skript ja auslesen kann in DB-Access übermittelt. Wie schon oben erwähnt klappt das ja mit den Photovoltaikdaten mit "wget" problemlos.
In dem Skript wird sich allerdings einfach in die Weboberfläche des Wechselrichters eingeloggt und die Daten herausgezogen.
Ich komme nur per TCP, Port 5000 an die Daten des Stromzählers ran. Da hängt ein Optokoppler dran mit Netzwerkanschluss.

- Gibt es in Python etwas ähnliches wie wget?
- Muss ich für DB-Access auch mit einem Connector wie bei MySQL arbeiten?

Ich hatte das z.B. in etwa so gedacht, das anstatt wie hier => save_smart_meter_db_prod(currentTimeBerlinInt, 0,'localhost',zaehlerstand,wirkleistung,wirkarbeitDelta, zaehlerprod)
in localhost zu schreiben, dann "einfach" in die Systemvariable meiner Homematic (IP-Adresse) zu schreiben. Mal ganz banal ausgedrückt.

Ich hoffe es ist eingemassen verständlich, was ich geschrieben habe. Ist für mich, der von Skripten keine Ahnung hat und die Zusammenhänge nicht immer deuten kann, nicht ganz einfach zu erklären.
BlackJack

@Awacs2000: Erste interessante Frage wäre wohl ob man mit Python und von Linux aus überhaupt an eine Access-Datenbank herankommt. Dafür bräuchte man ja irgendwie einen Treiber und soweit ich das in Erinnerung habe gibt's da nichts. Und selbst wenn dann ist das eine Lösung die wahrscheinlich kaum jemand einsetzt. Kann man da keine vernünftige Datenbank verwenden, oder zumindest MySQL? :-)
Awacs2000
User
Beiträge: 7
Registriert: Sonntag 11. Januar 2015, 14:46

BlackJack hat geschrieben:@Awacs2000: Erste interessante Frage wäre wohl ob man mit Python und von Linux aus überhaupt an eine Access-Datenbank herankommt. Dafür bräuchte man ja irgendwie einen Treiber und soweit ich das in Erinnerung habe gibt's da nichts. Und selbst wenn dann ist das eine Lösung die wahrscheinlich kaum jemand einsetzt. Kann man da keine vernünftige Datenbank verwenden, oder zumindest MySQL? :-)
Puh, ich habe leider keine Ahnung.Ich weiß nur, dass DB-Access im Zusammenspiel mit dem Bash-Skript funktioniert.
Vielleicht ist das ja für jemanden, der Ahnung von Shell-Skripten hat, ein einfaches, das Python-Skript umzuschreiben. Wer weiß!
Es wird da dort ja sicherlich auch möglich sein eine TCP-Abfrage über den Port 5000 zu realisieren.

Naja, wenn das Problem DB-Access ist, dann habe ich halt erst einmal Pech gehabt.
BlackJack

@Awacs2000: Vielleicht reden wir hier aneinander vorbei, bei Access dachte ich jetzt an eine Access-Datenbank. Bei dem Shellskript ist gar keine Datenbank im Spiel, jedenfalls kommt das mit keiner Datenbank in Berührungt sondern übergibt die Werte anscheinend über einen Webserver der auf dem Homematic-Gerät(?) läuft.

``wget`` führt HTTP-Anfragen aus, das geht auch mit Python. Ich würde da das `requests`-Modul empfehlen.

Natürlich ist es möglich eine TCP-Verbindung zu Port 5000 zu öffnen und damit zu kommunizieren, das macht das Python-Skript in Deinem Beitrag ja. Das wäre im Gegenteil wohl eher nichts für ``wget`` weil das nicht nur über TCP kommuniziert sondern da auch HTTP als Protokoll erwartet und auf dem Stromzähler scheint kein HTTP-Server zu laufen.

Das Problem sehe ich darin das man das Python-Skript nicht wirklich verwenden kann. Das sieht, wie bereits angemerkt wurde, nicht nur aus als wenn es von jemandem geschrieben wurde der keine grosse Ahnung vom Programmieren an sich hat, auch von Socketprogrammierung hätte derjenige gerne mehr wissen dürfen. Das ist nämlich fehlerhaft umgesetzt weil `recv()` nicht garantiert das auch tatsächlich so viele Bytes gelesen werden wie man angegeben hat, oder das alles was auf der Gegenseite ”auf einmal” gesendet wurde auch in einem `recv()`-Aufruf vollständig ausgelesen wurde.
Awacs2000
User
Beiträge: 7
Registriert: Sonntag 11. Januar 2015, 14:46

Wieso kann man das Skript nicht verwenden? Das hat jetzt erfolgreich 3 Jahre funktioniert und mir den Zählerstand usw. ausgelesen und in die Datenbank geschrieben.
Und nun sollte es doch möglich sein die Variable "Zaehlerstand" in Richtung der Haussteuerung zu senden anstatt in eine Datenbank zu schreiben.
Wäre das nicht POST möglich, da in meinem Photovoltaikanlagen-Shellskript ja auch nichts anderes gemacht wird als die Variablen an die cgi-Webadresse der Haussteuerung zu senden. Klappt ja auch.
Sprich, nimm dir den Wert der Variable "Zaehlerstand" und sende diesen zur angelegten Systemvariable "Zaehlerstand" auf der Haussteuerung.
Das muss doch möglich sein.
BlackJack

@Awacs2000: Das Skript ”funktioniert” aber das ist halt nicht garantiert weil es fehlerhaft umgesetzt ist. Wenn Du den Murks benutzen willst, dann benutze ihn halt.
Awacs2000
User
Beiträge: 7
Registriert: Sonntag 11. Januar 2015, 14:46

Ich würde das Skript ja gerne nutzen. Dafür benötige ich aber die Hilfe von euch, da ich ja nun leider nicht weiß, wie ich die Werte übergeben kann/könnte.
Awacs2000
User
Beiträge: 7
Registriert: Sonntag 11. Januar 2015, 14:46

Prinzipiell funktioniert es jetzt mit folgendem:

url = 'http://IP-der-Haussteuerung/addons/db/s ... d&value=%s' % zaehlerstand'
req = urllib2.Request(url)
response = urllib2.urlopen(req)
the_page = response.read()
print "%s" % the_page

Die Werte werden somit geholt und in meine Systemvariablen der Haussteuerung geschrieben:

Zaehlerstand : 3041
Wirkleistung : 265.0 W
Z.Produktion : 12982.0
3041.000000
265.000000
12982.000000

Bild

Das klappt soweit.

Allerdings läuft das immer nur maximal 3 mal und dann kommt folgendes:

Hole jetzt Information vom Smart Meter Stream
Zaehlerstand : 3041
Wirkleistung : 265.0 W
Z.Produktion : 12982.0
3041.000000
265.000000
12982.000000
Hole jetzt Information vom Smart Meter Stream
Zaehlerstand : 3041
Wirkleistung : 271.0 W
Z.Produktion : 12982.0
3041.000000
Traceback (most recent call last):
File "Stromzaehlerabfrage", line 143, in <module>
read_smart_meter()
File "Stromzaehlerabfrage", line 31, in read_smart_meter
calc_smart_meter(smlmsg)
File "Stromzaehlerabfrage", line 131, in calc_smart_meter
response = urllib2.urlopen(req)
File "/usr/lib/python2.7/urllib2.py", line 127, in urlopen
return _opener.open(url, data, timeout)
File "/usr/lib/python2.7/urllib2.py", line 407, in open
response = meth(req, response)
File "/usr/lib/python2.7/urllib2.py", line 520, in http_response
'http', request, response, code, msg, hdrs)
File "/usr/lib/python2.7/urllib2.py", line 445, in error
return self._call_chain(*args)
File "/usr/lib/python2.7/urllib2.py", line 379, in _call_chain
result = func(*args)
File "/usr/lib/python2.7/urllib2.py", line 528, in http_error_default
raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 500: Internal Server Error


Könnt ihr mir wenigstens da einen Tipp geben???

Danke!
Awacs2000
User
Beiträge: 7
Registriert: Sonntag 11. Januar 2015, 14:46

Für alle, die es interessiert, so läuft es jetzt bei mir.
Der "internal Serverfehler 500" kommt von der Homematic, da die teilweise zu lange beschäftigt ist. Das sieht man, wenn man den stage.cgi-Link über den Browser abschickt und mehrmals F5 drückt.
Diesen "unterbinde" ich mit dem "try/except".
Somit läuft das Script wenigstens weiter und schiebt die Werte eben erst beim nächsten oder übernächsten mal in die Systemvariablen der Homematic.
Mir reicht das. So schnell ändert sich der Zählerstand auch nicht. Und für den aktuellen Strom-Verbrauch ist das auch ok.

Ich denke mal, wer Ahnung von Python hat, bekommt das sicherlich besser hin. Die ganzen Meckerer in diesen Thread, denen das Skript nicht gefiel, wahrscheinlich sowieso.
Danke für NICHTS.

Code: Alles auswählen

#!/usr/bin/python

# Auslesen des EDL21-Zaehlerstandes per co.met COM Ethernet-IR-Lesekopf und Uebermittlung an die Homematic-Systemvariablen

def prodSystem():
        #0 Nein
        #1 Ja
        return 1

import time
import urllib,urllib2
import socket

def read_smart_meter():
        TCP_IP = "IP-des-Optokoppler"
        TCP_PORT = 5000
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((TCP_IP, TCP_PORT))
        dataBuffer = s.recv(1024)
        data = s.recv(10000)
        openbreak = 0
        openbreak = data.index("(")
        openbreak = openbreak + 1
        closingbreak = data.index(")")
        smlfilelength = closingbreak - openbreak
        smlmsg = data[openbreak:openbreak+smlfilelength]
        s.close()
        calc_smart_meter(smlmsg)

def calc_smart_meter(smart_stream):
        zaehlerstand = 0
        wirkleistung = 0
        print "Hole jetzt Information vom Smart Meter Stream"

        j = 0
        if "0100010800FF" in smart_stream:
                try:
                        j = smart_stream.index("0100010800FF")
                        zahlerstandHEX = smart_stream[j:j+100]
                        j2 = 0
                        j3 = 0
                        if "01621E52FF59" in zahlerstandHEX:
                                j2 = zahlerstandHEX.index("01621E52FF59")
                                j3 = zahlerstandHEX.index("017707")
                                ZS_HEX = zahlerstandHEX[(j2+12):j3]
                                decZS = int(ZS_HEX,16)
                                zaehlerstand = (decZS / 10000)
                                print "Zaehlerstand : %s kWh" % zaehlerstand
                        else:
                                print "Konnte den Zaehlerstand nicht finden"
                except:
                        print "Fehler in Methode A beim Zaehlerstand"

        else:
                print "Zaehlerstand nicht Abrufbar"
                zaehlerstand = 0

        k = 0
        if "0100100700FF" in smart_stream:
                try:
                        k = smart_stream.index("0100100700FF")
                        wirkleistungHEX = smart_stream[k:k+100]
                        k2 = 0
                        k3 = 0
                        if "55" in wirkleistungHEX:
                                k2 = wirkleistungHEX.index("55")
                                k3 = wirkleistungHEX.index("017707")
                                WL_HEX = wirkleistungHEX[k2+2:k3]
                                decWL = int(WL_HEX,16)
                                if WL_HEX[0:2] == "FF":
                                        decWLL = int("FFFFFFFF", 16)
                                        print "FULL: %s" % decWLL
                                        print "CURR: %s" % decWL
                                        decWL = decWL-decWLL
                                wirkleistung = float(decWL);
                                print "Wirkleistung  : %s Watt" % wirkleistung

                        else:
                                print "Konnte die Wirkleistung nicht finden"
                except:
                        print "Fehler in Methode A beim Zaehlerstand"

        else:
                print "Wirkleistung nicht Abrufbar"
                wirkleistung = 0

        if prodSystem() == 1:
                x = 0
                if "0100020800FF" in smart_stream:
                        x = smart_stream.index("0100020800FF")
                        prodZaHEX = smart_stream[x:x+100]
                        x2 = 0
                        x3 = 0
                        if "01621E52FF59" in prodZaHEX:
                                x2 = prodZaHEX.index("01621E52FF59")
                                x3 = prodZaHEX.index("017707")
                                PZ_HEX = prodZaHEX[x2+12:x3]
                                decWL = int(PZ_HEX,16)
                                zaehlerprod = float(decWL/10000);
                                print "Z.Produktion  : %s kWh" % zaehlerprod
                        else:
                                print "Konnte die Zaehlerstand Produktion  nicht finden"
                else:
                        print "Produktion nicht abrufbar"

        print "Uebermittle Zaehlerstand an Homematic"

        try:
                url = 'http://IP-der-Homematic/addons/db/state.cgi'
                values = {'item' : 'Zaehlerstand','value' : zaehlerstand}
                data = urllib.urlencode(values)
                req = urllib2.Request(url, data)
                response = urllib2.urlopen(req)
                the_page = response.read()
        except:

                print "Fehler bei der Uebermittlung. Die Homematic aktuell ausgelastet"

        time.sleep(10)

        print "Uebermittele Wirkleistung"

        try:
                url = 'http://IP-der-Homematic/addons/db/state.cgi'
                values = {'item' : 'Wirkleistung','value' : wirkleistung}
                data = urllib.urlencode(values)
                req = urllib2.Request(url, data)
                response = urllib2.urlopen(req)
                the_page = response.read()
        except:

                print "Fehler bei der Uebermittlung.Die Homematic aktuell ausgelastet"

        time.sleep(10)

        print "Uebermittele PV-Zaehlerstand"

        try:
                url = 'http://IP-der-Homematic/addons/db/state.cgi'
                values = {'item' : 'PV-Einspeisung','value' : zaehlerprod}
                data = urllib.urlencode(values)
                req = urllib2.Request(url, data)
                response = urllib2.urlopen(req)
                the_page = response.read()

        except:

                print "Fehler bei der Uebermittlung.Die Homematic aktuell ausgelastet"

        print "FERTIG UEBERMITTELT"

while(1==1):
        read_smart_meter()

        time.sleep(10)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Awacs2000 hat geschrieben:Ich denke mal, wer Ahnung von Python hat, bekommt das sicherlich besser hin. Die ganzen Meckerer in diesen Thread, denen das Skript nicht gefiel, wahrscheinlich sowieso.
Danke für NICHTS.
Bei dem Programm würde ich nicht von "funktioniert" sprechen. Das läuft eigentlich nur durch Glück, kann aber zu jeder Zeit abschmieren. Das hat auch nichts mit Python zu tun, du hast da einfach ganz grundsätzliche Fehler drin. Das wurde ja aber alles schon genannt.
Das Leben ist wie ein Tennisball.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Awacs2000 hat geschrieben:Danke für NICHTS.
Wenn du wirklich nichts über saubere Programmierung mit Python aus diesem Thread gelernt hast, dann tust du mir wirklich leid. Üben, üben, üben und wenn die Dokumentation nicht mehr weiterhilft oder du dir unsicher bist einfach nachfragen, dann wird das schon noch.
acidbath
User
Beiträge: 21
Registriert: Mittwoch 26. Januar 2011, 19:10

N'abend.

Ich klinke mich hier mal ein, weil ich ebenfalls eine HomeMatic-CCU daheim habe. Mir geht's nicht um die eigentliche Funktionalität (das Programm läuft), sondern um Verbesserungsvorschläge. Leider komme ich extrem selten dazu, mal wieder den Python-Interpreter anzuschmeißen und war entsprechend froh über diese kleine 'Fingerübung' - jetzt würde mich nur ein kurzes Feedback interessieren, wo's ggf. hapert...

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8
import urllib2


IP = '192.168.27.20'
ADDRESS = 'http://{0}:8181/tclrega.exe'.format(IP)

def set_hm_variable(variable, value=''):
    command = """var sys_var = dom.GetObject('{}');
    Write(sys_var.State({}));""".format(variable, value)
    try:
        url_response = urllib2.urlopen(ADDRESS, command)
    except urllib2.URLError as e:
        print 'Error accessing CCU: {}'.format(e)
        return False
    return url_response.read().startswith('true')

def get_hm_variable(variable):
    command = """Write(dom.GetObject('{}').State());""".format(variable)
    try:
        url_response = urllib2.urlopen(ADDRESS, command)
    except urllib2.URLError as e:
        print 'Error accessing CCU: {}'.format(e)
        return None
    return url_response.read().split('<xml>')[0]

def main():
    if set_hm_variable('Versuch', 42):
        print 'Variable erfolgreich gesetzt.'
    else:
        print 'Variable konnte nicht geändert werden.'
    print get_hm_variable('Versuch')

if __name__ == '__main__':
    main()
Dank und Gruß,
Daniel
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dem Modul würde ich zunächst eine Funktion spendieren, mit der du ganz allgemein Kommandos absetzen kannst. Das Setzen und das Abfragen sind, bis auf kleine Unterschiede, ja quasi identisch. In Python ist es außerdem unüblich den Erfolg eines Aufrufs explizit mittels Wahrheitswerten im Rückgabewert unterzubringen. Wenn ein Fehler auftritt, dann sollte einfach eine Exception geworfen werden. Dann wirst du auch gleich die Vermischung von Ausgabe und Logik los.

Das ``return None`` in Zeile 25 ist überflüssig, da reich ein einfaches ``return``. Ist nichts angegeben, so wird automatisch None zurückgegeben. Statt "e" würde ich auch "error" schreiben, das lässt sich besser verstehen.
Das Leben ist wie ein Tennisball.
acidbath
User
Beiträge: 21
Registriert: Mittwoch 26. Januar 2011, 19:10

Hallo EyDu,

Danke für Deine Antwort.
Würdest Du im konkreten Fall dann eine eigene, neue Exception werfen, oder einfach die aktuelle weiterreichen?

Code: Alles auswählen

IP = '192.168.1.2'
ADDRESS = 'http://{0}:8181/tclrega.exe'.format(IP)

def send_hm_command(command):
    try:
        url_response = urllib2.urlopen(ADDRESS, command)
    except urllib2.URLError:
        raise
    response = url_response.read()
    if response.find('<xml>'):
        return response.split('<xml>')[0]
Ich frage, weil mir die Code-Doppelung (ich hätte zweimal ein "except urllib2.URLError", sowohl in send_hm_command als auch der übergeordneten Funktion) etwas komisch vorkommt - deshalb griff ich vermutlich ursprünglich auch sofort auf die Variante mit dem zurückgegebenen Boolean zurück.

Gruß,
Daniel
BlackJack

@acidbath: Wenn man bei der aktuellen bleibt braucht man nichts weiterreichen sondern lässt einfach das ``try``/``except`` komplett weg. Nur ein ``raise`` im ``except`` macht doch gar keinen Sinn.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

acidbath hat geschrieben:Würdest Du im konkreten Fall dann eine eigene, neue Exception werfen, oder einfach die aktuelle weiterreichen?
In dem konkreten Minibeispiel lohnt sich eine eigene Ausnahme nicht. Die würde ich, wie BlackJack schon geschrieben hat, einfach nach oben reichen lassen. Wenn es komplexer wird, dann musst du einfach mal selber etwas probieren. Über Vererbung kannst du ganze Hierarchien von Exceptions aufbauen und behandeln, das ist aber nicht immer sinnvoll.
Das Leben ist wie ein Tennisball.
acidbath
User
Beiträge: 21
Registriert: Mittwoch 26. Januar 2011, 19:10

@BlackJack: stimmt, ursprünglich hatte ich noch eine logging-Ausgabe im except-Block - ein nackiges raise bringt exakt gar nichts. :D

@EyDu: da ich bisher noch nicht mit eigenen Exceptions rumgespielt habe, nehme ich das jetzt mal zum Anlaß, mir das Thema etwas anzuschauen...
spirit22
User
Beiträge: 1
Registriert: Dienstag 3. Februar 2015, 14:12

Ich möchte nun aber die Werte nicht in eine MySQL-Datenbank schreiben lassen, sondern mit DB-Access der CCU verknüpfen.
Das habe ich aktuell schon mit den Daten meiner PV-Anlage.
Hallo,

ich habe genau das vor (PV Anlage) - komme aber nicht wirklich weiter. Kannst du mir deine Scripte zur Verfügung stellen?

Vielen Dank!
Antworten