Solar Auswertung - Proxy

Begonnen von maxx8888, 03 Dezember 2016, 10:02:16

Vorheriges Thema - Nächstes Thema

maxx8888

Hallo!

Ich habe mir eine kleine Solaranlage mit Envertech Inverter und Auswerteeinheit zugelegt.

Diese Auswerteeinheit überträgt Daten direkt auf die envertechportal.com und bietet wie es aussieht keine Möglichkeit direkt zu lesen.

Deshalb habe ich mal die Pakete gesnifft die an die Homepage übermittelt werden. Die Codierung ist relativ einfach und ich kann mittlerweile die Pakete direkt dekodieren.
Ich würde gerne ein Module/Device für Fhem erstellen das diese Daten liest und anschliessend Plots erstellen lassen.

Jetzt stellt sich die Frage wie ich mich mit Fhem in diese Kommunikation einklinken kann. Meine Idee wäre DNS Lookups des Envertech Teils mit dem lokalen Fhem Server zu beantworten.
Das würde heißen das sich das Envertech Teil auf einem TCP Port des Fhem Servers anmelden versucht und die Daten sendet.

Wäre es möglich so eine Art Proxy am Fhem Server zu haben, das die Daten einfach 1 zu 1 zwischen Auswerteeinheit <-> envertechportal.com durchschleust jedoch die Daten mitliest?

Vielleicht gibt es schon ein ähnliches Module in fhem?

Danke schon mal für Infos :-)

Lg,
Maxx

fhemmatic

Hallo,
cool. Bisher war ich noch nicht dazu gekommen mal den Datenstrom zu sniffen.
Aber so wie auch das Portal abgesichert ist, habe ich schon vermutet das die Daten die da übertragen werden, leicht auszuwerten sind.

Nur mal ein bisschen Brainstorming:
Die Enverbridge bekommt ja via DHCP eine IP. Habe jetzt noch nicht nachgeschaut ob der fest verdrahtet eine IP anspricht oder einen DNS Namen.
Ansonsten via DNS ihm den Namen des FHEM Servers unterjubeln. Aber dann kommen die Daten bei Envertech nicht mehr an.

Was nutzt Du als FHEM Server oder sonst so im Netz?
Den FHEM Server in den Routing-Modus setzen. An einem Bein die Enverbridge die dann als DFG den FHEM Server hat. Und an dem anderen Bein Richtung Internet weiterreichen. Und schon kann man mit den üblichen Tools den Datenstrom Richtung envertecportal.com aufsaugen.

Fehlt dann noch die Aufbereitung der Daten für FHEM.

Viele Grüße

maxx8888

Hi!

Als Fhem Server habe ich eine kleine Debian VM neben anderen VMs auf meinen Nas laufen.

Ja, korrekt. Die Enverbridge macht eine DNS Anfrage auf envertecportal.com und dorthin sendet sie dann in etwa alle 10-15min Daten.
Als Router kommt bei mir eine pfSense zum Einsatz. DNS re-routen zum Fhem Server wäre kein Problem.

Würde aber wenn gerne eine Lösung anstreben, die rein auf Fhem läuft da es ja sonst anderen Usern warscheinlich nicht helfen würde.

Weil Du fragst was i so im Netz hab:
Cisco switches, pfSense Router, Ubiquiti Wlan, umgebautes Ultimate Qnap Nas, und vieeeeele Homematic Devices via Homematic Lan Interface.

Fhem Server in den Routing Modus setzen? Klingt ja schon mal intressant :-)

Falls es Dich interssiert, share ich gerne meine "Findings" von der Envertec Kommunikation.

Bin halt beim Fhem Module schreiben blutiger Anfänger.
Eigentlich habe ich noch nicht wirklich eine Idee wie ich das angehen soll.

Viele Grüsse

WhyTea

Moin
Gibt es hier neue Erkenntnisse? Ich stehe ebenfalls vor der Anschaffung einer solchen Anglage.

Gruß
Daniel

peewag

Hallo,

ich bin auch gerade am mit-sniffen der Pakete, aber habe leider noch keine großen Erfolge beim entschlüsseln. Könntst ihr mir bitte ein paar Tips geben, was die Pakete beinhalten?

lg Peter 

LPBBSB15

Hallo, hat jemand etwas über die Daten herausbekommen, die Übertragen werden?
Sind das nur SerienNr und Leistung und evt. Fehlercodes?

Oder werden auch wie bei SMA Ströme, Spannungen, Frequenz, ... übertragen ?
Vielen Dank schon einmal.

easy12

Hi,

ich gehe davon aus, das all Daten wie im Envertechportal übertragen werden - d.h. AC, DC, Frequenz, Power, Temp

Code sieht wie folgt aus, bin aber noch nicht dahinter gekommen wie die Daten zu decodieren sind.

XXXX = ID vom EVB200,
YYYY= erste Wechselrichter,
ZZZZ = zweite Wechselrichter
die 0000 sind Placeholder für die Daten der max. möglichen Wechselrichter

Rohdaten:

680296681004XXXXXXXX00000000940910001200YYYYYYYY01023dfa020c000155561c2738b6320b020000000000000000000000ZZZZZZZZ01023eda027400013dcb1c2738b6320b020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c716


selbe Timestamp im Portal:
#1 31 DC, 226.8 AC, 50.04 Frequenz, 8.2 Watt, Total 10.67, 16.3 Temp
#2 31.4 DC, 226.8 AC, 50.04 F, 9.8 Watt, Total 9.93, 16.3 Temp
#3 30.7, 226.8, 50.01, 7.1, 10.67, 15.8
#4 31.5, 226.8, 50.01, 9   ,  9.93, 15.8
#5 30.7, 225  , 50.02, 6.6,  10.67, 15.8
#6 30.6, 225  , 50.02, 8.6,   9.93, 15.8
#7 22.2, 223.2, 49.99, 3.3, 10.67, 15.3
#8 24.1, 223.2, 49.99, 4.5,  9.93, 15.3
#9 21.3, 223.8, 50    , 0.6, 10.67, 13.3
#10 22.2, 223.8, 50  , 1.2,  9.93, 13.3
#11 15.3, 227.3, 50  ,   0, 10.67, 10.3
#12 30.1, 226.8, 50.03, 0,  9.93, 10.3

Der Interesante Teil:

#1 01023dfa0 20c000 155561c2738b6320b020
#2 01023eda0 274000 13dcb1c2738b6320b020
#3 01023d6d0 1c9000 155771be938b63202020
#4 01023ef30 240000 13dcb1be938b63202020
#5 01023d700 1a9000 155771beb38423204020
#6 01023d330 226000 13dcb1beb38423204020
#7 01022c6b0 0d6000 155771ba837cf31fe020
#8 010230380 11e000 13dcb1ba837cf31fe020
#9 01022a9800 28000 155771aa537f43200020
#10 01022c5b00 4b000 13dcb1aa537f43200020
#11 01021e8800 00000 15577191338d33200465c450
#12 01023c4c00 00000 13dcb192238b63208024



Offensichtlich ist es ja nach den Wechselrichter ID Hex, aber keine offensichtliche Umrechnung nach Decimal/Fraction/BaseXY.

maxx8888@ Kannst du uns erleuchten!? Bzw. hat jemand anderes es schon raus?

Gruß Martin

easy12

#7
Ich bin ein wenig weiter gekommen:

Immer 4er Blöcke (außer kWh) nach der ID:
ID                      + 0102   + 3de6 + 1b9e + 000155e0 + 26bf + 3a08 + 3203
WechselrichterID + ????#1 +  DC + Watt  + kWh-Total + Temp + AC   + Frequenz
#1 Code welche Info jetzt kommt

Berechnung der Werte:

Frequenz
4er Block in 2 einzelne Hexwerte
#1 HEX->DEZ
31 -> 49
32 -> 50

#2 HEX->DEZ
0d->13
13/255 = 0,0509
320d=50,0509

Watt && AC
Block komplett von HEX in DEZ
1b9e->7070
7070/64=110,468

3671->13937
13937/64=217,76

DC
31,2 3e6e 3e58
31   3df0
30,9 3de6 3dd2 3dd0
30,8 3d88 3da6
30,7 3d66 3d7c 3d56
30,6 3d34
30,5 3cec
29,9 3bb8 3bc4 -> 15288 15300

HEX->DEZ / 512
15300/512 = 29,882

Total kWh
10,68 000155e0
10,70 00015676 -> 87670/8192=10,7019
10,72 0001571a
10,74 00015793
10,75 0001581c -> 10,75341

TotalkWh HEXBlock 8 Stellen  -> DEZ / 8192


noch nicht bestimmt:
TEMP

15,8 1beb
37,4 26b4 26b9
37,5 26bf
39,7 27de 27dd
40,2 2816

Noch ein paar Werte zum Spielen:

0102 3de6 1b9e 0001 55e0 26bf 3a08 320300
30.9, 232.1, 110.5, 50.01, 37.5, Apr.21 14:04,2017, 10.68

0102 3d88 3671 0001 55e0 2676 3aae 320200
30.8, 234.7 ,217.8, 50.01,36.9, Apr.21 14:07,2017, 10.68

0102 3e6e 3d08 0001 5676 26b4 3ab9 31fd00
31.2, 234.9, 244.1, 49.99, 37.4, Apr.21 14:10,2017, 10.7

0102 3c58 39ee 0001 571a 26f3 3a6c 31fc00
30.2, 233.7, 231.7, 49.98, 37.9, Apr.21 14:13,2017, 10.72

0102 3bc4 2061 0001 571a 273a 39ae 31fe00
29.9, 230.7, 129.5, 49.99, 38.5, Apr.21 14:18,2017, 10.72

0102 3da6 3981 0001 5793 2766 3a43 31fc00
30.8, 233, 230, 49.98, 38.8, Apr.21 14:21,2017, 10.74

0102 3df0 15ad 0001 581c 275 83eb 320900
31, 231.7, 86.7, 50.04, 38.7, Apr.21 14:24,2017, 10.75


Gruß Martin

LPBBSB15

Hallo,
leider hatte ich keine Benachrichtigung erhalten und habe die letzten Stunden damit verbracht das ebenfalls zu analysieren.
Ich kann das so weit bestätigen.

Zur Temperatur bitte mal prüfen  (( T1 * 256 + T2 ) / 128 ) - 40 = T [°C]
ob das bei Dir / Euch paßt.

easy12

#9
Hi, Respekt! Hab die Temperatur mal mit 3 meiner Werte durchprobiert und alle haben gepasst. Wie soll man darauf bitte kommen ;)

Hier noch 2 Anregungen bzw. Überlegungen - ich habe davon (noch) nichts umgesetzt.

Die Hacklösung:
- Permanent TCPDUMP mit e.g. raspberry pi. Dafür brauch man aber z.b managebaren Switch oder Firewall für port-mirror.
-> Auswertung der Daten

Die Proxylösung, die für die meisten Heimsetups funktionieren sollte:
Wer kein extra DNS server oder andersweitige Möglichkeiten mit Firewall oder ähnlichen hat um DNS Lookups umzuschreiben.
https://adrian-jagusch.de/2015/03/domains-abfangen-mit-der-fritzbox-als-dns-server/
+ TCP proxy um Daten abzufangen und weiterzuleiten. Python Code zum entschlüsseln muss natürlich noch eingebettet werden.
http://voorloopnul.com/blog/a-python-proxy-in-less-than-100-lines-of-code/

Ähnliches gibt sicherlich auch in anderen Sprachen...

Gruß Martin

LPBBSB15

Hallo,

hat schon jemand Erfolg mit Berechnung der CRC gehabt ?   Hiermit bin ich leider auch nicht weitergekommen:  http://crccalc.com/

Viele Grüße Herbert

easy12

Zitat von: LPBBSB15 am 03 Mai 2017, 18:28:37,
hat schon jemand Erfolg mit Berechnung der CRC gehabt ?   Hiermit bin ich leider auch nicht weitergekommen:  http://crccalc.com/

Leider nein, aber ich bin über http://reveng.sourceforge.net/ gestolpert was quasi reverse engineering von CRC bietet. Ich hab leider gerade keinen Rechner mit power um es durchlaufen zu lassen, der pi braucht halt ewig.

Für die kurzen messages wäre syntax "reveng-1.5.1# ./reveng -w 368 -l -s hex1 hex2 hex3" Dann rödelt er...


Ansonsten kann ich zumindest Erfolge vermelden bzgl. Proxy - ich hab den 100 Zeilen Code von oben verwendet und noch die Python Funktionen hinzugepackt. Auf dem Pi den DNS Server installiert und ne Außnahme für die eine Webadresse eingerichtet und lasse DHCP die IP vom DNS Server vergeben. DNS override: e.g. https://serverfault.com/questions/18748/overriding-some-dns-entries-in-bind-for-internal-networks

Wie Ihr unten seht übergebe ich allerdings nicht an FHEM  :-\ , sondern an Pimatic, aber die Pushvariante kann ein FHEM versierter einfach anpassen.

Hin und wieder gibt es Socketerror, den ich abfange und er trennt und verbindet sich beim nächsten push neu. Das läuft jetzt schon rund 2 Tage ohne Probleme. Die Proxy.py  einfach über cron bei Systemstart ausführen lassen,

@reboot /root/scripts/proxystart.sh


Folgender Code startet die proxy.py immer neu falls es mal nen Error gibt.

#!/bin/bash

until /root/scripts/proxy.py; do
    echo "Proxy.py crashed with exit code $?.  Respawning.." >&2
    sleep 1
done


Hier der Proxycode inkl. Anpassungen und Berechnungen (Define + Calc kann zusammengefasst werden, aber getrennt ist übersichtlicher):

#!/usr/bin/python
# This is a simple port-forward / proxy, written using only the default python
# library. If you want to make a suggestion or fix something you can contact-me
# at voorloop_at_gmail.com
# Distributed over IDC(I Don't Care) license
from __future__ import division
import socket
import select
import time
import sys
import os

# Changing the buffer_size and delay, you can improve the speed and bandwidth.
# But when buffer get to high or delay go too down, you can broke things
buffer_size = 4096
delay = 0.0001
forward_to = ('www.envertecportal.com', 10013)
DEBUG = False

class Forward:
    def __init__(self):
        self.forward = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def start(self, host, port):
        try:
            self.forward.connect((host, port))
            return self.forward
        except Exception, e:
            print e
            return False

class TheServer:
    input_list = []
    channel = {}

    def __init__(self, host, port):
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server.bind((host, port))
        self.server.listen(200)

    def main_loop(self):
        self.input_list.append(self.server)
        while 1:
            time.sleep(delay)
            ss = select.select
            inputready, outputready, exceptready = ss(self.input_list, [], [])
            for self.s in inputready:
                if self.s == self.server:
                    self.on_accept()
                    break

                try:
                    self.data = self.s.recv(buffer_size)
                    if len(self.data) == 0:
                        self.on_close()
                        break
                    else:
                        self.on_recv()
                except socket.error:
                    if DEBUG:
                        print ('Socket error')
                        time.sleep(1)
                    #self.on_close()
                else:
                    continue

    def on_accept(self):
        forward = Forward().start(forward_to[0], forward_to[1])
        clientsock, clientaddr = self.server.accept()
        if forward:
            print clientaddr, "has connected"
            self.input_list.append(clientsock)
            self.input_list.append(forward)
            self.channel[clientsock] = forward
            self.channel[forward] = clientsock
        else:
            print "Can't establish connection with remote server.",
            print "Closing connection with client side", clientaddr
            clientsock.close()

    def on_close(self):
        print self.s.getpeername(), "has disconnected"
        #remove objects from input_list
        self.input_list.remove(self.s)
        self.input_list.remove(self.channel[self.s])
        out = self.channel[self.s]
        # close the connection with client
        self.channel[out].close()  # equivalent to do self.s.close()
        # close the connection with remote server
        self.channel[self.s].close()
        # delete both objects from channel dict
        del self.channel[out]
        del self.channel[self.s]

    def extract(self, data, wrind):
        pos1 = 40 + (wrind*64)
        # Define
        d_wr_id = data[pos1:pos1+8]
        d_hex_dc = data[pos1+12:pos1+12+4]
        d_hex_power = data[pos1+16:pos1+16+4]
        d_hex_total = data[pos1+20:pos1+20+8]
        d_hex_temp = data[pos1+28:pos1+28+4]
        d_hex_ac = data[pos1+32:pos1+32+4]
        d_hex_freq = data[pos1+36:pos1+36+4]
        d_hex_remaining = data[pos1+40:pos1+40+24]

        # Calculation
        d_dez_dc = '{0:.2f}'.format(int(d_hex_dc, 16)/512)
        d_dez_power = '{0:.2f}'.format(int(d_hex_power, 16)/64)
        d_dez_total = '{0:.2f}'.format(int(d_hex_total, 16)/8192)
        d_dez_temp = '{0:.2f}'.format(((int(d_hex_temp[0:2], 16)*256+int(d_hex_temp[2:4], 16))/ 128)-40)
        d_dez_ac = '{0:.2f}'.format(int(d_hex_ac, 16)/64)
        d_dez_freq = '{0:.2f}'.format(int(d_hex_freq[0:2], 16)+int(d_hex_freq[2:4], 16)/ 256)

        if int(d_wr_id) != 0:
            result = {'wrid' : d_wr_id, 'dc' : d_dez_dc, 'power' : d_dez_power, 'totalkwh' : d_dez_total, 'temp' : d_dez_temp, 'ac' : d_dez_ac, 'freq' : d_dez_freq, 'remaining' : d_hex_remaining}
            return result

    def submit_data(self, wrdata):
        # Can be https as well. Also: if you use another port then 80 or 443 do not forget to add the port number.
        pimatic_server = 'IP FOR PIMATIC SERVER'
        # user and password. I prefer a special posting user having a role of varposter with only  "variables": "write" in the varposter role. Rest to "none" or false.
        pimatic_user = 'removed'
        pimatic_pass = 'removed'
        pim_user_pass = pimatic_user + ':' + pimatic_pass
        curl_prefix = 'curl --silent --insecure -X PATCH --header "Content-Type:application/json" --data \'{"type": "value", "valueOrExpression": "'
        pim_server_url = pimatic_server + '/api/variables/'
        #print len(wrdata)
        #print wrdata

        for wrdict in wrdata:
            print wrdict['wrid']
            values = 'ac', 'dc', 'temp', 'power', 'totalkwh', 'freq'
            for value in values:
                os.system(curl_prefix + wrdict[value] + '"}\'  --user "' + pim_user_pass + '" ' + pim_server_url + "wrid" + wrdict['wrid'] + "_" + value)

    def process_data(self, data):
        datainhex = data.encode('hex')
        print datainhex
        wr = []
        wr_index = 0
        wr_index_max = 20
        while True:
            if DEBUG:
                print "Processing Data"
            response = self.extract(datainhex, wr_index)
            if response:
                if DEBUG:
                    print "."
                wr.append(response)
            wr_index += 1
            if wr_index >= wr_index_max:
                break
        if DEBUG:
            print "Processed Data!"
            print wr
            print "Submitting Data"
        self.submit_data(wr)

    def on_recv(self):
        data = self.data
        print len(data)
        if len(data) == 662:
            self.process_data(data)
            #print data.encode('hex')
        self.channel[self.s].send(data)

if __name__ == '__main__':
        server = TheServer('', 10013)
        try:
            server.main_loop()
        except KeyboardInterrupt:
            print "Ctrl C - Stopping server"
            sys.exit(1)


Gruß Martin

Marie

#12
Moin Leute,


habe mittlerweile auch so eine Envertec Kombi....hat sich schon etwas weiteres bei der Auswertung ergeben? -ich hänge noch am DNS-programmieren der Fritzbox... klappt irgendwie nicht. Wäre aber schon sehr daran interessiert, die Daten abzufangen und nicht mehr nach China zu schicken... ;-)


LG


Marie


PS: Die Geschichte mit der Fritzbox klappt wohl so nicht mehr... kann die Konfigurationsdateien nicht ändern aufgrund der CRC lässt sie sich nicht zurückschreiben... auch nicht mit dem FBEditor. FritzOs ist aktuell....  6.83
Banana Pi & FHEM2FHEM Raspberry,RS485 Modbus Stromzähler UMG96, diverse Schaltsteckdosen 433 MHz, 868 MHz, MYSENSORS Temperatursensoren , Smartvisu, Homekit & Siri, Geofency, Zwave Rauchmelder & Steckdosen & Garagensteuerung, TabletUi mit BananaPi M2Ultra im Wohnmobil, Homebridge usw.usw.

LPBBSB15

Hallo,

hat sich zufällig jemand mit dem PLC MI200E von Miartech beschäftigt ?   (Gern auch per PN)

Viele Grüße Herbert

Uwe_Eta20

Hallo liebe Gemeinde,

ich wollte mal nachfragen, ob es realistisch ist, sowas als Modul zu bauen.
Sowas würde ich mir natürlich gerne in einer Übersicht anzeigen lassen (ja, es gibt ja auch ein Portal).

Oder, man geht auch über HTTPMOD, das mache ich vom Ofen ( ETA ) auch, hier gibt es bereits vorbereitete Variablen, die man über REST Webservices bequem holen kann.
Aber, wo fängt man hier an, gibt es jemand, der das bereits integriert hat?

Danke
Uwe