Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

problem when using with briefcase to make an android app to show data && problem running in Termux on android #119

Open
eltoro0815 opened this issue Jun 10, 2024 · 4 comments

Comments

@eltoro0815
Copy link

Hi:)

There is a popular python library briefcase.

You can make all Sort of Apps with python code based on this library.

Today I tried to make an Android app:

"""
shows actual data from your e3dc system
"""

import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW

from e3dc import E3DC

USERNAME = '[email protected]'
PASS = 'md5hashofpassword'
SERIALNUMBER = 'S10-xxxxxxxxxxxxxxxxxx'
CONFIG = {}


class eltoro0815e3dcapp(toga.App):

    def startup(self):

        main_box = toga.Box(style=Pack(direction=COLUMN))

        label = toga.Label("App gestartet.",
                           style=Pack(padding=10, font_size=14))

        def show_data(*args):
            e3dc_obj = E3DC(E3DC.CONNECT_WEB,
                        username=USERNAME,
                        password=PASS,
                        serialNumber=SERIALNUMBER,
                        isPasswordMd5=False,
                        configuration=CONFIG)
            label.text = "Warten auf Antwort ..."
            yield 0.1  # needed to redraw the label

            data = e3dc_obj.poll(keepAlive=True)

            label.text = f"""Hausverbrauch: {data['consumption']['house']}
Wallbox: {data['consumption']['wallbox']}
Batterie: {data['consumption']['battery']}
Battery %: {data['stateOfCharge']}%
PV Wechselrichter: {data['production']['solar']}
ext. Quelle: {data['production']['add']}
Netz: {data['production']['grid']}
"""

        button = toga.Button(
            "Status abrufen",
            on_press=show_data,
            style=Pack(padding=5),
        )

        main_box.add(button)
        main_box.add(label)

        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = main_box
        self.main_window.show()




def main():
    return eltoro0815e3dcapp()

When I run this on an android device the app hangs if I push the button.
The following line causes this.

e3dc_obj = E3DC(E3DC.CONNECT_WEB,
                        username=USERNAME,
                        password=PASS,
                        serialNumber=SERIALNUMBER,
                        isPasswordMd5=False,
                        configuration=CONFIG)

Seems like there is a problem with some network traffic.

Are there known limitations on this library caused by network limitations?

@eltoro0815
Copy link
Author

I tried to run a minimal version in termux on my android phone.
test.py

from e3dc import E3DC

USERNAME = '[email protected]'
PASS = 'md5password'
SERIALNUMBER = 'S10-number'
CONFIG = {}

print("web connection")
e3dc_obj = E3DC(E3DC.CONNECT_WEB, username=USERNAME, password=PASS, serialNumber = SERIALNUMBER, isPasswordMd5=False, configuration = CONFIG)
# connect to the portal and poll the status. This might raise an exception in case of failed login. This operation is performed with Ajax
print(e3dc_obj.poll(keepAlive=True))
#print(e3dc_obj.get_pvi_data(keepAlive=True))
print(e3dc_obj.get_battery_data()['rsoc'])
e3dc_obj.disconnect()

When i run this I get:

web connection
Traceback (most recent call last):
 File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/e3dc/_e3dc.py", line 226, in sendRequest
   self.rscp.connect()
 File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/e3dc/_e3dc_rscp_web.py", line 417, in connect
   raise RequestTimeoutError
e3dc._e3dc_rscp_web.RequestTimeoutError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
 File "/storage/emulated/0/acode/test.py", line 9, in <module>
   e3dc_obj = E3DC(E3DC.CONNECT_WEB, username=USERNAME, password=PASS, serialNumber = SERIALNUMBER, isPasswordMd5=False, configuration = CONFIG)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/e3dc/e3dc.py", line 141, in __init_
   self.get_system_info_static(keepAlive=True)
 File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/e3dc/_e3dc.py", line 817, in get_system_info_static
   self.sendRequestTag(RscpTag.EMS_REQ_DERATE_AT_PERCENT_VALUE, keepAlive=True)
 File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/e3dc/_e3dc.py", line 264, in sendRequestTag
   return self.sendRequest(
          ^^^^^^^^^^^^^^^^^
 File "/data/data/com.termux/files/usr/lib/python3.11/site-packages/e3dc/_e3dc.py", line 238, in sendRequest
   raise SendError("Max retries reached")
e3dc._e3dc.SendError: Max retries reached

@eltoro0815
Copy link
Author

eltoro0815 commented Jun 10, 2024

Running test_websocket.py in Termux works as expected:

import websocket
ws = websocket.WebSocket()
ws.connect("ws://echo.websocket.events")
ws.send("Hello, Server")
print(ws.recv())
ws.close()

Output:

echo.websocket.events sponsored by Lob.com

@eltoro0815 eltoro0815 changed the title problem when using with briefcase to make an android app to show data problem when using with briefcase to make an android app to show data && problem running in Termux on android Jun 10, 2024
@eltoro0815
Copy link
Author

eltoro0815 commented Jun 12, 2024

I did some research with the new portal (my.e3dc.com)

Here is a script which logs in to get the Bearer Token and listens to a Websocket to get the actual data of your system.

import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, parse_qs
import websocket

# Start einer Session, um Cookies beizubehalten
session = requests.Session()


# Erste Anfrage an die SAML-Service-Provider-Login-URL:
# https://e3dc.e3dc.com/auth-saml/service-providers/customer/login?app=e3dc
# Gibt 302 als Antwort

initial_url = 'https://e3dc.e3dc.com/auth-saml/service-providers/customer/login?app=e3dc'
response = session.get(initial_url, allow_redirects=False)
print('1) [GET] Erste Anfrage an: ', initial_url)


# Weiterleitung zu ->
# https://customer.sso.e3dc.com/saml2/idp/SSOService.php?SAMLRequest=...
# Gibt 302 als Antwort
redirect_url = response.headers['Location']
response = session.get(redirect_url, allow_redirects=False)
print('2) [GET] Weiterleitung zu: ', redirect_url)

# Weiterleitung zu ->
# https://customer.sso.e3dc.com/module.php/core/loginuserpass.php?AuthState=...
# Gibt 200 als Antwort
login_page_url = response.headers['Location']
response = session.get(login_page_url)
print('3) [GET] Weiterleitung zur Login Seite: ', login_page_url)

if response.status_code == 200:

    # Extrahieren des AuthState-Werts
    soup = BeautifulSoup(response.text, 'html.parser')
    auth_state_input = soup.find('input', {'name': 'AuthState'})
    auth_state_value = auth_state_input['value'] if auth_state_input else None

    if auth_state_value:
        # Senden der Login-Daten
        login_data = {
            'username': 'YourUserName',  # Ersetzen Sie dies durch den tatsächlichen Benutzernamen
            'password': 'YourPasswordInPlainText',      # Ersetzen Sie dies durch das tatsächliche Passwort
            'AuthState': auth_state_value
        }

        # Submit Button des Formular klicken -->
        # https://customer.sso.e3dc.com/module.php/core/loginuserpass.php?
        login_url = 'https://customer.sso.e3dc.com/module.php/core/loginuserpass.php'
        response = session.post(login_url, data=login_data, allow_redirects=False)
        print("4) [POST] Abschicken des Anmeldeformulars mit Username und Passwort: ", login_url)

        if response.status_code == 200:
            # Extrahieren des SAMLResponse-Werts
            soup = BeautifulSoup(response.text, 'html.parser')
            saml_response_input = soup.find('input', {'name': 'SAMLResponse'})
            saml_response_value = saml_response_input['value'] if saml_response_input else None

            if saml_response_value:
                # Senden des SAMLResponse-Werts
                post_data = {
                    'SAMLResponse': saml_response_value
                }

                # Assert aufrufen
                #
                assert_url = 'https://e3dc.e3dc.com/auth-saml/service-providers/customer/assert'
                response = session.post(assert_url, data=post_data, allow_redirects=False)
                print("5) [POST] Abschicken des Dummy Formulars das SAMLResponse enthält: ", assert_url)

                redirect_url = response.headers['Location']

                parsed_url = urlparse(redirect_url)
                query_params = parse_qs(parsed_url.query)
                token_value = query_params.get('token', [None])[0]
                print("------------------------------------------------------------------------------")
                print("Bearer Token: ", token_value)
                print("------------------------------------------------------------------------------")

            else:
                print("SAMLResponse-Wert konnte nicht extrahiert werden.")
        else:
            print("Fehler beim Laden der SAML-Response-Seite:", response.status_code, response.text)
    else:
        print("AuthState-Wert konnte nicht extrahiert werden.")
else:
    print("Fehler beim Laden der Login-Seite:", response.status_code, response.text)


def on_message(ws, message):
    print(f"Received message: {message}")

def on_error(ws, error):
    print(f"Error: {error}")

def on_close(ws, close_status_code, close_msg):
    print("Connection closed")

def on_open(ws):
    # Hier können Sie Nachrichten senden, wenn die Verbindung geöffnet ist
    ws.send("Ihre Nachricht hier")


# Ersetzen Sie die URL durch die URL Ihres WebSocket-Servers
websocket_url = f"wss://e3dc.e3dc.com/storages/YOUR-SERIAL-NUMBER-WITHOUT-THE-PREFIX/status/ws?authorization={token_value}"

ws = websocket.WebSocketApp(websocket_url,
                                on_open=on_open,
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)

ws.run_forever()
+ THIS works on my Phone with Termux :) :) :)

@inc90
Copy link

inc90 commented Jul 9, 2024

I was having a similar problem recently, but it turned out to be the E3DC websocket endpoint configuration. I changed from
wss://s10.e3dc.com/ws/ to wss://s10.e3dc.com/ws (note the missing /) as per #106 (comment).

I changed the REMOTE_ADDRESS variable in the file python-e3dc/e3dc/_e3dc_rscp_web.py

It might be updated now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants