fsantini / python-e3dc

Python API for querying E3/DC systems through the manufacturer's portal
MIT License
72 stars 23 forks source link

Web connection seems not to work anymore #106

Closed ghiottolino closed 5 months ago

ghiottolino commented 10 months ago

I have been using python-e3dc with the web connection to get some data out of e3dc reliable for ca 1.5 year. suddently, in the last few months, the webconnection functionalities is not working for me anymore, and my test script always fails:

Traceback (most recent call last): File "/home/ntesser/workspaces/private/python-e3dc/e3dc/_e3dc.py", line 225, in sendRequest self.rscp.connect() File "/home/ntesser/workspaces/private/python-e3dc/e3dc/_e3dc_rscp_web.py", line 427, in connect raise RequestTimeoutError e3dc._e3dc_rscp_web.RequestTimeoutError

I wonder if this is due to the new portal of e3dc and others are expiencing this problem or if it´s something off with my setup?

vchrisb commented 10 months ago

Which version of python-e3dc are you using? Since 0.8.3 the websocket is consistently used. Before that change, for poll() parsing of the website was used.

ghiottolino commented 10 months ago

I was using commit of Jan 24, 2022 of e3dc_rscp_web: https://github.com/fsantini/python-e3dc/commits/master/e3dc/_e3dc_rscp_web.py

so I guess it was a version 7.X.

However it does not seem that any major changes from WSS to website parsing happens in the meantime.

I tryed with the newest version and a bunch of versions between 7.x and current version, and always getting the same error. My impression is that at least for my credentials then endpoint "wss://s10.e3dc.com/ws/" is not working as expected.

Any tip on how to debug that endpoint?

vchrisb commented 10 months ago

The older versions did used to call https://s10.e3dc.com/s10/phpcmd/cmd.php for poll(). https://github.com/fsantini/python-e3dc/blob/bff23bbded99f08e2a2d56503dcd45b51e87df37/e3dc/_e3dc.py#L204

Please try again with the latest release and share the full exception.

ghiottolino commented 9 months ago

Hi, sorry, I missed following up on this:

Here is the full stacktrace (I´ve updated python-e3dc to the last update of 4th of dec).

python e3dc.py 
web connection
Traceback (most recent call last):
  File "/home/ntesser/workspaces/private/python-e3dc/e3dc/_e3dc.py", line 225, in sendRequest
    self.rscp.connect()
  File "/home/ntesser/workspaces/private/python-e3dc/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 "/home/ntesser/workspaces/private/python-e3dc/e3dc.py", line 10, in <module>
    e3dc_obj = E3DC(E3DC.CONNECT_WEB, username=USERNAME, password=PASS, serialNumber = SERIALNUMBER, isPasswordMd5=False, configuration = CONFIG)
  File "/home/ntesser/workspaces/private/python-e3dc/e3dc/_e3dc.py", line 140, in __init__
    self.get_system_info_static(keepAlive=True)
  File "/home/ntesser/workspaces/private/python-e3dc/e3dc/_e3dc.py", line 820, in get_system_info_static
    self.sendRequestTag(RscpTag.EMS_REQ_DERATE_AT_PERCENT_VALUE, keepAlive=True)
  File "/home/ntesser/workspaces/private/python-e3dc/e3dc/_e3dc.py", line 263, in sendRequestTag
    return self.sendRequest(
  File "/home/ntesser/workspaces/private/python-e3dc/e3dc/_e3dc.py", line 237, in sendRequest
    raise SendError("Max retries reached")
e3dc._e3dc.SendError: Max retries reached

I am using Ubuntu 22.04, python 3.9.12.

The test script I am using is the same as the example one in the readme.md and I double checked the value a few times and tried a few variations. e.g. serialnumber with or without 'S10-' in front. but always with the same issue. (connection timeout).

from e3dc import E3DC

USERNAME = 'yyy @gmail.com'
PASS = 'yyy'
SERIALNUMBER = 'yyy'
CONFIG = {"powermeters": [{"index": 6}]}

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))
e3dc_obj.disconnect()
fu commented 8 months ago

I have the same issue. Python3.11 and latest commit. Connection via local works, ie user + password are correct.

    ...: e3dc_obj = E3DC(
    ...:     E3DC.CONNECT_LOCAL,
    ...:     username=USERNAME,
    ...:     password=PASS,
    ...:     ipAddress=IP,
    ...:     key=KEY,
    ...:     configuration = {},
    ...: )
    ...: # The following connections are performed through the RSCP interface
    ...: print(e3dc_obj.poll(keepAlive=True))
    ...: print(e3dc_obj.get_pvi_data(keepAlive=True))
    ...: e3dc_obj.disconnect()
local connection
{'autarky': 98.90287780761719, 'consumption': {'battery': 345, 'house': 730, 'wallbox': 0}, 'production': {'solar': 1061, 'add': 0, 'grid': 14}, 'selfConsumption': 99.07200622558594, 'stateOfCharge': 6, 'time': datetime.datetime(2024, 1, 21, 14, 21, 40, 853, tzinfo=datetime.timezone.utc)}
{'acMaxApparentPower': 4000.0, 'cosPhi': {'active': None, 'value': None, 'excited': None}, 'deviceState': {'connected': True, 'working': True, 'inService': False}, 'frequency': {'under': None, 'over': None}, 'index': 0, 'lastError': '3 0x0', 'maxPhaseCount': 3, 'maxStringCount': 2, 'onGrid': True, 'phases': {0: {'power': 643.0, 'voltage': 225.5, 'current': 2.950000047683716, 'apparentPower': 665.0, 'reactivePower': 0.0, 'energyAll': 14756097.0, 'energyGridConsumption': 6566.0}, 1: {'power': 0.0, 'voltage': 227.10000610351562, 'current': 0.0, 'apparentPower': 0.0, 'reactivePower': 0.0, 'energyAll': 9516854.0, 'energyGridConsumption': 550.0}, 2: {'power': 0.0, 'voltage': 225.6999969482422, 'current': 0.0, 'apparentPower': 0.0, 'reactivePower': 0.0, 'energyAll': 9996090.0, 'energyGridConsumption': 585.0}}, 'powerMode': 1, 'serialNumber': '<DELETED>', 'state': '0xb32315', 'strings': {0: {'power': 627.0, 'voltage': 584.0, 'current': 1.0700000524520874, 'energyAll': 21601691.0}, 1: {'power': 434.0, 'voltage': 422.0, 'current': 1.0199999809265137, 'energyAll': 15285519.0}}, 'systemMode': 2, 'temperature': {'max': 130.0, 'min': -30.0, 'values': [33.900001525878906, 33.900001525878906, 43.20000076293945, 36.099998474121094]}, 'type': 3, 'version': ' MAIN HW06 2.060', 'voltageMonitoring': {'thresholdTop': None, 'thresholdBottom': None, 'slopeUp': None, 'slopeDown': None}}

Remote:

In [17]: 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))
    ...: e3dc_obj.disconnect()
web connection
---------------------------------------------------------------------------
RequestTimeoutError                       Traceback (most recent call last)
File ~/e3dc-data/python-e3dc/e3dc/_e3dc.py:225, in E3DC.sendRequest(self, request, retries, keepAlive)
    224 if not self.rscp.isConnected():
--> 225     self.rscp.connect()
    226 result = self.rscp.sendRequest(request)

File ~/e3dc-data/python-e3dc/e3dc/_e3dc_rscp_web.py:417, in E3DC_RSCP_web.connect(self)
    416 if not self.isConnected():
--> 417     raise RequestTimeoutError

RequestTimeoutError: 

During handling of the above exception, another exception occurred:

SendError                                 Traceback (most recent call last)
Cell In[17], line 2
      1 print("web connection")
----> 2 e3dc_obj = E3DC(
      3     E3DC.CONNECT_WEB, 
      4     username=USERNAME, 
      5     password=PASS, 
      6     serialNumber=SERIALNUMBER, 
      7     isPasswordMd5=False, 
      8     configuration = CONFIG
      9 )
     10 # connect to the portal and poll the status. This might raise an exception in case of failed login. This operation is performed with Ajax
     11 print(e3dc_obj.poll(keepAlive=True))

File ~/e3dc-data/python-e3dc/e3dc/_e3dc.py:140, in E3DC.__init__(self, connectType, **kwargs)
    131         self.password = hashlib.md5(
    132             kwargs["password"].encode("utf-8")
    133         ).hexdigest()
    134     self.rscp = E3DC_RSCP_web(
    135         self.username,
    136         self.password,
    137         "{}{}".format(self.serialNumberPrefix, self.serialNumber),
    138     )
--> 140 self.get_system_info_static(keepAlive=True)

File ~/e3dc-data/python-e3dc/e3dc/_e3dc.py:820, in E3DC.get_system_info_static(self, keepAlive)
    813 def get_system_info_static(self, keepAlive: bool = False):
    814     """Polls the static system info via rscp protocol.
    815 
    816     Args:
    817         keepAlive (bool): True to keep connection alive. Defaults to False.
    818     """
    819     self.deratePercent = (
--> 820         self.sendRequestTag(RscpTag.EMS_REQ_DERATE_AT_PERCENT_VALUE, keepAlive=True)
    821         * 100
    822     )
    824     self.deratePower = self.sendRequestTag(
    825         RscpTag.EMS_REQ_DERATE_AT_POWER_VALUE, keepAlive=True
    826     )
    827     self.installedPeakPower = self.sendRequestTag(
    828         RscpTag.EMS_REQ_INSTALLED_PEAK_POWER, keepAlive=True
    829     )

File ~/e3dc-data/python-e3dc/e3dc/_e3dc.py:263, in E3DC.sendRequestTag(self, tag, retries, keepAlive)
    244 def sendRequestTag(
    245     self, tag: str | int | RscpTag, retries: int = 3, keepAlive: bool = False
    246 ):
    247     """This function uses the RSCP interface to make a request for a single tag.
    248 
    249     Does make retries in case of exceptions like Socket.Error
   (...)
    261         e3dc.SendError: if retries are reached
    262     """
--> 263     return self.sendRequest(
    264         (tag, RscpType.NoneType, None), retries=retries, keepAlive=keepAlive
    265     )[2]

File ~/e3dc-data/python-e3dc/e3dc/_e3dc.py:237, in E3DC.sendRequest(self, request, retries, keepAlive)
    235         retry += 1
    236         if retry > retries:
--> 237             raise SendError("Max retries reached")
    239 if not keepAlive:
    240     self.rscp.disconnect()

SendError: Max retries reached

Serial number +- "S10-" makes no difference.

vchrisb commented 6 months ago

It looks like E3DC changed their websocket endpoint configuration. We are using wss://s10.e3dc.com/ws/ which is not working anymore but wss://s10.e3dc.com/ws is. I'll update the code.