Skip to content

Commit

Permalink
Fix discovery and add timer cancelation
Browse files Browse the repository at this point in the history
  • Loading branch information
mletenay committed Apr 30, 2024
1 parent 6c43b88 commit 5d90ac5
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 19 deletions.
30 changes: 17 additions & 13 deletions goodwe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import asyncio
import logging
from typing import Type

from .const import GOODWE_TCP_PORT, GOODWE_UDP_PORT
from .dt import DT
Expand Down Expand Up @@ -74,22 +73,27 @@ async def discover(host: str, port: int = GOODWE_UDP_PORT, timeout: int = 1, ret
model_name = response[5:15].decode("ascii").rstrip()
serial_number = response[31:47].decode("ascii")

inverter_class: Type[Inverter] | None = None
i: Inverter | None = None
for model_tag in ET_MODEL_TAGS:
if model_tag in serial_number:
logger.debug("Detected ET/EH/BT/BH/GEH inverter %s, S/N:%s.", model_name, serial_number)
inverter_class = ET
for model_tag in ES_MODEL_TAGS:
if model_tag in serial_number:
logger.debug("Detected ES/EM/BP inverter %s, S/N:%s.", model_name, serial_number)
inverter_class = ES
for model_tag in DT_MODEL_TAGS:
if model_tag in serial_number:
logger.debug("Detected DT/MS/D-NS/XS/GEP inverter %s, S/N:%s.", model_name, serial_number)
inverter_class = DT
if inverter_class:
i = inverter_class(host, port, 0, timeout, retries)
i = ET(host, port, 0, timeout, retries)
break
if not i:
for model_tag in ES_MODEL_TAGS:
if model_tag in serial_number:
logger.debug("Detected ES/EM/BP inverter %s, S/N:%s.", model_name, serial_number)
i = ES(host, port, 0, timeout, retries)
break
if not i:
for model_tag in DT_MODEL_TAGS:
if model_tag in serial_number:
logger.debug("Detected DT/MS/D-NS/XS/GEP inverter %s, S/N:%s.", model_name, serial_number)
i = DT(host, port, 0, timeout, retries)
break
if i:
await i.read_device_info()
logger.debug("Connected to inverter %s, S/N:%s.", i.model_name, i.serial_number)
return i

except InverterError as ex:
Expand Down
4 changes: 2 additions & 2 deletions goodwe/inverter.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ async def _read_from_socket(self, command: ProtocolCommand) -> ProtocolResponse:
except MaxRetriesException:
self._consecutive_failures_count += 1
raise RequestFailedException(f'No valid response received even after {self._protocol.retries} retries',
self._consecutive_failures_count)
self._consecutive_failures_count) from None
except RequestFailedException as ex:
self._consecutive_failures_count += 1
raise RequestFailedException(ex.message, self._consecutive_failures_count)
raise RequestFailedException(ex.message, self._consecutive_failures_count) from None

@abstractmethod
async def read_device_info(self):
Expand Down
17 changes: 13 additions & 4 deletions goodwe/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class InverterProtocol:
def __init__(self, host: str, port: int, timeout: int, retries: int):
self._host: str = host
self._port: int = port
self._timer: asyncio.TimerHandle | None = None
self.timeout: int = timeout
self.retries: int = retries
self.protocol: asyncio.Protocol | None = None
Expand Down Expand Up @@ -78,6 +79,8 @@ def connection_lost(self, exc: Optional[Exception]) -> None:

def datagram_received(self, data: bytes, addr: Tuple[str, int]) -> None:
"""On datagram received"""
if self._timer:
self._timer.cancel()
try:
if self.command.validator(data):
logger.debug("Received: %s", data.hex())
Expand All @@ -89,7 +92,8 @@ def datagram_received(self, data: bytes, addr: Tuple[str, int]) -> None:
except RequestRejectedException as ex:
logger.debug("Received exception response: %s", data.hex())
self.response_future.set_exception(ex)
self._close_transport()
finally:
self._close_transport()

def error_received(self, exc: Exception) -> None:
"""On error received"""
Expand All @@ -113,7 +117,7 @@ def _send_request(self, command: ProtocolCommand, response_future: Future) -> No
logger.debug("Sending: %s%s", self.command,
f' - retry #{self._retry}/{self.retries}' if self._retry > 0 else '')
self._transport.sendto(self.command.request)
asyncio.get_running_loop().call_later(self.timeout, self._retry_mechanism)
self._timer = asyncio.get_running_loop().call_later(self.timeout, self._retry_mechanism)

def _retry_mechanism(self) -> None:
"""Retry mechanism to prevent hanging transport"""
Expand All @@ -130,7 +134,10 @@ def _retry_mechanism(self) -> None:

def _close_transport(self) -> None:
if self._transport:
self._transport.close()
try:
self._transport.close()
except RuntimeError:
logger.debug("Failed to close transport.")
self._transport = None
# Cancel Future on connection close
if self.response_future and not self.response_future.done():
Expand Down Expand Up @@ -180,6 +187,8 @@ def connection_lost(self, exc: Optional[Exception]) -> None:

def data_received(self, data: bytes) -> None:
"""On data received"""
if self._timer:
self._timer.cancel()
try:
if self.command.validator(data):
logger.debug("Received: %s", data.hex())
Expand Down Expand Up @@ -231,7 +240,7 @@ def _send_request(self, command: ProtocolCommand, response_future: Future) -> No
logger.debug("Sending: %s%s", self.command,
f' - retry #{self._retry}/{self.retries}' if self._retry > 0 else '')
self._transport.write(self.command.request)
asyncio.get_running_loop().call_later(self.timeout, self._timeout_mechanism)
self._timer = asyncio.get_running_loop().call_later(self.timeout, self._timeout_mechanism)

def _timeout_mechanism(self) -> None:
"""Retry mechanism to prevent hanging transport"""
Expand Down

0 comments on commit 5d90ac5

Please sign in to comment.